Une chose qui le rend déroutant est que les fonctions "populaires" aiment bind
et <*>
sont orientées vers la pratique. Mais pour comprendre les concepts, il est plus facile d'examiner d'abord les autres fonctions. Il convient également de noter que les monades se démarquent car elles sont un peu sur-typées par rapport aux autres concepts connectés. Je vais donc commencer par les foncteurs à la place.
Les foncteurs proposent une fonction (en notation Haskell) fmap :: (Functor f) => (a -> b) -> f a -> f b
. En d'autres termes, vous disposez d'un contexte dans f
lequel vous pouvez intégrer une fonction. Comme vous pouvez l'imaginer, presque tout est un foncteur. Listes, Peut-être, Soit, fonctions, E / S, tuples, analyseurs ... Chacun représente un contexte dans lequel une valeur peut apparaître. Vous pouvez donc écrire des fonctions extrêmement polyvalentes qui fonctionnent dans presque tous les contextes en utilisant fmap
ou sa variante en ligne <$>
.
Quelles autres choses voulez-vous faire avec les contextes? Vous voudrez peut-être combiner deux contextes. Donc , vous voudrez peut - être obtenir une généralisation de zip :: [a] -> [b] -> [(a,b)]
par exemple comme ceci: pair :: (Monoidal f) => f a -> f b -> f (a,b)
.
Mais parce que c'est encore plus utile dans la pratique, les bibliothèques Haskell proposent à la place Applicative
, qui est une combinaison de Functor
et Monoidal
, Et aussi de Unit
, qui ajoute simplement que vous pouvez réellement mettre des valeurs "à l'intérieur" de votre contexte avec unit
.
Vous pouvez écrire des fonctions extrêmement génériques en déclarant simplement ces trois choses sur le contexte dans lequel vous travaillez.
Monad
est juste une autre chose que vous pouvez dire en plus de cela. Ce que je n'ai pas mentionné auparavant, c'est que vous avez déjà deux façons de combiner deux contextes: vous pouvez non seulement pair
les utiliser, mais vous pouvez également les empiler, par exemple, vous pouvez avoir une liste de listes. Dans le contexte d'E / S, un exemple serait une action d'E / S qui peut lire d'autres actions d'E / S à partir d'un fichier, vous auriez donc un type FilePath -> IO (IO a)
. Comment pouvons-nous nous débarrasser de cet empilement pour obtenir une fonction exécutable IO a
? C'est là Monad
qu'intervient s join
, il nous permet de combiner deux contextes empilés du même type. Il en va de même pour les analyseurs, Peut-être etc. Et bind
est juste un moyen plus pratique d'utiliserjoin
Un contexte monadique n'a donc qu'à offrir quatre choses et il peut être utilisé avec presque toutes les machines développées pour les E / S, les analyseurs, les pannes, etc.