Una cosa che rende confusionaria è che le funzioni "popolari" come bind
e <*>
sono orientate alla praxis. Ma per capire i concetti è più facile guardare prima ad altre funzioni. Vale anche la pena notare che le monadi si distinguono perché sono un po 'overhyped rispetto ad altri concetti connessi.
Quindi inizierò con i funtori invece.
I Functional offrono una funzione (in notazione Haskell) fmap :: (Functor f) => (a -> b) -> f a -> f b
. In altre parole, hai un contesto f
in cui puoi sollevare una funzione. Come puoi immaginare, quasi tutto è un funtore. Elenchi, Forse, O, funzioni, I / O, tuple, parser ... Ciascuno rappresenta un contesto in cui può apparire un valore. Quindi puoi scrivere funzioni estremamente versatili che funzionano in quasi tutti i contesti usando fmap
o la sua variante in linea <$>
.
Quali altre cose vuoi fare con i contesti? Potresti voler combinare due contesti. Quindi potresti voler ottenere una generalizzazione di zip :: [a] -> [b] -> [(a,b)]
ad esempio in questo modo: pair :: (Monoidal f) => f a -> f b -> f (a,b)
.
Ma poiché è ancora più utile in pratica, le librerie Haskell offrono invece Applicative
, che è una combinazione di Functor
e Monoidal
, e anche di Unit
, che aggiunge solo che puoi effettivamente inserire valori "dentro" il tuo contesto con unit
.
Puoi scrivere funzioni estremamente generiche semplicemente dichiarando queste tre cose sul contesto in cui stai lavorando.
Monad
è solo un'altra cosa che puoi aggiungere. Ciò che non ho menzionato prima è che hai già due modi per combinare due contesti: puoi non solo pair
, ma puoi anche raggrupparli, ad es. puoi avere una lista di liste. Nel contesto I / O, un esempio potrebbe essere un'azione di I / O in grado di leggere altre azioni I / O da un file, quindi si dovrebbe avere un tipo FilePath -> IO (IO a)
. Come possiamo sbarazzarci di quell'impilamento per ottenere una funzione eseguibile IO a
? Ecco dove arriva Monad
s join
, ci consente di combinare due contesti impilati dello stesso tipo. Lo stesso vale per i parser, forse ecc. E bind
è solo un modo più pratico di usare join
Quindi un contesto monadico deve offrire solo quattro cose e può essere utilizzato con quasi tutti i macchinari sviluppati per I / O, per i parser, per i guasti ecc.