2013-03-31 14 views
49

Mi sto confondendo molto con questi tre concetti.Semplici esempi per illustrare Category, Monoid e Monad?

Esiste qualche semplice esempio per illustrare le differenze tra Categoria , Monoid e Monade?

Sarebbe molto utile se c'è un'illustrazione di questi concetti astratti.

+12

Hai letto il [Typeclassopedia] (http://www.haskell.org/haskellwiki/Typeclassopedia)? – dave4420

+0

Grazie per il vostro consiglio. Avrei dovuto leggerlo prima. – Znatz

+1

[Le Monade sono come i burritos] (http://blog.plover.com/prog/burritos.html). Veramente. –

risposta

91

Questo probabilmente non è la risposta che state cercando, ma qui si va in ogni modo:

Un modo davvero storto di guardare monadi & co.

Un modo di considerare concetti astratti come questi è collegarli a concetti di base, come le operazioni di elaborazione di elenchi ordinari. Quindi, si potrebbe dire che,

  • Una categoria generalizza l'operazione (.).
  • Un monoide generalizza l'operazione (++).
  • Un functor generalizza l'operazione map.
  • Un funtore applicativo generalizza l'operazione zip (o zipWith).
  • Una monade generalizza l'operazione concat.

A Categoria

Una categoria è costituita da un insieme (o una classe) di oggetti e mazzo di frecce che ogni collegano due degli oggetti. Inoltre, per ogni oggetto, dovrebbe esserci una freccia di identità che collega questo oggetto a se stesso. Inoltre, se è presente una freccia (f) che termina su un oggetto e un'altra (g) che inizia dallo stesso oggetto, dovrebbe essere presente anche una freccia composta denominata g . f.

In Haskell questo è modellato come un typeclass che rappresenta la categoria di tipi Haskell come oggetti.

class Category cat where 
    id :: cat a a 
    (.) :: cat b c -> cat a b -> cat a c 

Gli esempi di base di una categoria sono funzioni. Ogni funzione collega due tipi, per tutti i tipi, c'è la funzione id :: a -> a che collega il tipo (e il valore) a se stesso. La composizione delle funzioni è la composizione ordinaria delle funzioni.

Insomma, categorie in base di Haskell sono cose che si comportano come funzioni, vale a dire si può mettere uno dopo l'altro con una versione generalizzata di (.).

Un Monoide

Un monoid è un insieme con un elemento unitario e un'operazione associativa. Questo è modellato in Haskell come:

class Monoid a where 
    mempty :: a 
    mappend :: a -> a -> a 

Esempi comuni di monoidi includono:

  • insieme degli interi, l'elemento 0, e l'operazione (+).
  • set di numeri interi positivi, l'elemento 1 e l'operazione (*).
  • insieme di tutte le liste, la lista vuota [] e l'operazione (++).

Questi sono modellati in Haskell come

newtype Sum a = Sum {getSum :: a} 
instance (Num a) => Monoid (Sum a) where 
    mempty = Sum 0 
    mappend (Sum a) (Sum b) = Sum (a + b) 

instance Monoid [a] where 
    mempty = [] 
    mappend = (++) 

monoidi sono abituati a 'combinare' e accumulare cose. Ad esempio, la funzione mconcat :: Monoid a => [a] -> a può essere utilizzata per ridurre un elenco di somme a somma singola o un elenco nidificato in un elenco semplice. Consideralo come una sorta di generalizzazione delle operazioni (++) o (+) che in un modo "uniscono" due cose.

un funtore

Un funtore in Haskell è una cosa che generalizza abbastanza direttamente l'operazione map :: (a->b) -> [a] -> [b]. Invece di mappare su un elenco, esegue il mapping sulla struttura , ad esempio un elenco, un albero binario o anche un'operazione IO. Funtori sono modellate come questo:

class Functor f where 
    fmap :: (a->b) -> f a -> f b 

Contrasto questo per la definizione della funzione normale map.

Un applicativi Functor

funtori applicativi possono essere visti come le cose con una zipWith un'operazione generalizzata. I Functor mappano su strutture generali una alla volta, ma con un functor Applicativo puoi comprimere due o più strutture. Per l'esempio più semplice, è possibile utilizzare applicativi per zip insieme due interi all'interno del tipo Maybe:

pure (+) <*> Just 1 <*> Just 2 -- gives Just 3 

Si noti che la struttura può influenzare il risultato, ad esempio:

pure (+) <*> Nothing <*> Just 2 -- gives Nothing 

Contrasto questo al solito zipWith funzione:

zipWith (+) [1] [2] 

Invece di di soli liste, i lavori applicativi per tutti i tipi di strutture. Inoltre, il trucco intelligente con pure e (<*>) generalizza lo zipping per funzionare con qualsiasi numero di argomenti. Per vedere come funziona, controllare i seguenti tipi mantenendo il concetto di funzioni parzialmente applicate a mano:

instance (Functor f) => Applicative f where 
    pure :: a -> f a 
    (<*>) :: f (a -> b) -> f a -> f b 

noti anche la somiglianza tra fmap e (<*>).

monade

Monadi sono spesso utilizzati per modellare diversi contesti computazionali, come la non-deterministico, o lato-effectful calcoli. Dal momento che ci sono già troppi tutorial su Monad, mi limiterò a raccomandare lo The best one, invece di scriverne un altro.

In relazione alle normali funzioni di elaborazione dell'elenco, le monadi generalizzano la funzione concat :: [[a]] -> [a] per lavorare con molti altri tipi di strutture oltre alle liste.Come semplice esempio, l'operazione monadica join può essere utilizzato per appiattire nidificate Maybe valori:

join (Just (Just 42)) -- gives Just 42 
join (Just (Nothing)) -- gives Nothing 

Come è legato all'utilizzo di Monadi come mezzo di calcoli strutturazione? Considera un esempio di giocattolo in cui esegui due query consecutive da un database. La prima query ti restituisce un valore chiave, con il quale desideri eseguire un'altra ricerca. Il problema qui è che il primo valore è racchiuso all'interno di Maybe, quindi non è possibile eseguire una query direttamente. Invece, come forse è un Functor, potresti invece fmap il valore di ritorno con la nuova query. Questo ti darebbe due valori nidificati Maybe come sopra. Un'altra query risulterebbe in tre livelli di Maybe s. Questo sarebbe piuttosto difficile da programmare con, ma un monadico join ti offre un modo per appiattire questa struttura e lavorare con un solo livello di Maybe s.

(credo che sarò editing questo post molto prima che abbia un senso ..)

+1

+1. Oh, e 'concat :: [[a]] -> [a]'. – phg

+0

'mempty = 0' dovrebbe essere' mempty = Sum 0'. – snak

+5

Mi piace questa risposta, ma potreste voler sottolineare che l'istanza standard 'Applicativa' per' [] 'non è quella zippy, ma il prodotto cartesiano. La non utile lista di zippy monad è valida solo su liste di lunghezza costante e il suo 'join' sta prendendo la diagonale. –