Una cosa che lo confonde è che le funzioni "popolari" piacciono bind
e <*>
sono orientate alla prassi. Ma per capire i concetti è più facile guardare prima altre funzioni. Vale anche la pena notare che le monadi si distinguono perché sono un po 'overhyped rispetto ad altri concetti collegati. Quindi inizierò con i funzione.
I Functor offrono una funzione (nella notazione di Haskell) fmap :: (Functor f) => (a -> b) -> f a -> f b
. In altre parole, hai un contesto in f
cui puoi sollevare una funzione. Come puoi immaginare, quasi tutto è un funzione. Elenchi, forse, entrambe le funzioni, I / O, tuple, parser ... Ognuno rappresenta un contesto in cui può apparire un valore. Quindi puoi scrivere funzioni estremamente versatili che funzionano in quasi ogni contesto usando fmap
o la sua variante in linea <$>
.
Quali altre cose vuoi fare con i contesti? Potresti voler combinare due contesti. Così si potrebbe desiderare di ottenere una generalizzazione zip :: [a] -> [b] -> [(a,b)]
per esempio come questo: pair :: (Monoidal f) => f a -> f b -> f (a,b)
.
Ma poiché è ancora più utile nella pratica, le librerie Haskell invece offrono Applicative
, che è una combinazione di Functor
e Monoidal
, e anche di Unit
, che aggiunge semplicemente che puoi effettivamente mettere i valori "dentro" il tuo contesto unit
.
Puoi scrivere funzioni estremamente generiche semplicemente affermando queste tre cose sul contesto in cui stai lavorando.
Monad
è solo un'altra cosa che puoi affermare in più. Quello che non ho menzionato prima è che hai già due modi per combinare due contesti: non solo puoi pair
, ma puoi anche impilarli, ad esempio puoi avere un elenco di elenchi. Nel contesto I / O, un esempio potrebbe essere un'azione I / O in grado di leggere altre azioni I / O da un file, quindi si avrà un tipo FilePath -> IO (IO a)
. Come possiamo liberarci di quello stacking per ottenere una funzione eseguibile IO a
? Ecco dove arriva Monad
s join
, ci permette di combinare due contesti sovrapposti dello stesso tipo. Lo stesso vale per i parser, forse ecc. Ed bind
è solo un modo più pratico da usarejoin
Quindi un contesto monadico deve offrire solo quattro cose e può essere utilizzato con quasi tutti i macchinari sviluppati per l'I / O, per i parser, per i guasti, ecc.