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.