J'ai lu beaucoup de messages qui expliquent ce que sont les monades, comment unit
et bind
fonctionnent, certains plongeant directement dans la théorie des catégories si abstraite (pour moi au moins) qui fait saigner les yeux, certains l'ignorant complètement et touchant à des analogies étranges de burritos, boîtes et autres.
Après quelques semaines d'étude et beaucoup de neurones frits, (je pense) je comprends comment fonctionnent les Monades. Mais il y a encore une chose qui échappe à ma compréhension, quelque chose que peu de messages abordent (sauf pour les entrées-sorties et l'état):
POURQUOI?
Pourquoi les monades sont-elles importantes? Pourquoi sont-ils si importants? Quels sont les problèmes qu'ils résolvent? Ces problèmes peuvent-ils être résolus uniquement avec les Monades ou existe-t-il d'autres moyens?
Réponses:
Vous n'avez pas besoin de monades pour résoudre quoi que ce soit. Ils rendent simplement certaines choses plus simples. Beaucoup de gens deviennent trop abstraits et théoriques pour expliquer les monades. La plupart du temps, les monades sont un modèle qui revient sans cesse dans la programmation. En reconnaissant ce modèle, nous pouvons simplifier notre code et éviter de réimplémenter certaines fonctions.
Pour Haskell, d'un point de vue concret, la chose la plus visible permise par les monades est la notation . La compréhension des listes en Haskell et dans d'autres langues profite également largement des monades. Vous pouvez également créer des bibliothèques comme Control.Monad .
Tous ces éléments fournissent des simplifications utiles, et une fois que vous l'avez implémenté pour une monade, vous l'obtenez automatiquement pour toutes les monades. C'est l'une des principales raisons pour lesquelles la réutilisation du code est tellement plus facile pour la programmation fonctionnelle que les autres paradigmes.
la source
IO
c'est la monade la plus en vue de Haskell , mais je ne listais pas d'exemples de monades individuelles. Je listais des exemples des abstractions globales qu'ils permettent. J'essayais de comprendre pourquoi, par exemple, le premier gars à penser à utiliser une monade pour IO penserait que c'est une bonne idée en général.Il est plus facile à comprendre si vous regardez les monades particulières et voyez quels problèmes elles résolvent. Par exemple, à Haskell:
IO: Permet à IO d'être représenté dans le système de type, de sorte que vous pouvez clairement séparer les fonctions pures des fonctions exécutant les IO.
Liste: permet d'effectuer des compréhensions de listes et des calculs nodéterministes.
Peut-être: une meilleure alternative aux nulls, et supportant quelque chose de comparable à l'opérateur de coalescence nulle de C #.
Parsec: DSL pratique pour écrire des analyseurs.
Il est donc facile (j'espère) de voir la justification des différentes monades, car elles sont toutes assez utiles. Mais les problèmes qu'ils résolvent sont également très différents et, à première vue, ils ne semblent pas avoir grand-chose en commun, sauf qu'ils sont tous liés à une logique de chaînage des opérations. Les monades sont utiles car elles vous permettent de créer une telle variété d'outils.
Les exemples ci-dessus pourraient-ils être mis en œuvre sans monades? Certes, ils pourraient être implémentés de manière ad hoc, mais le fait d'avoir des monades intégrées dans le langage permet un support direct de la langue comme la
do
-notation qui fonctionne avec toutes les monades.la source
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 dansf
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 utilisantfmap
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 deFunctor
etMonoidal
, Et aussi deUnit
, qui ajoute simplement que vous pouvez réellement mettre des valeurs "à l'intérieur" de votre contexte avecunit
.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 seulementpair
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 typeFilePath -> IO (IO a)
. Comment pouvons-nous nous débarrasser de cet empilement pour obtenir une fonction exécutableIO a
? C'est làMonad
qu'intervient sjoin
, 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. Etbind
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.
la source
Monads vous permet d'exprimer divers calculs non purs ainsi que de simplifier le code
Et, surtout sans compromettre les constructions de langage pur et en tirer un langage plus propre
la source
Maybe
ne sont pas liées à quelque chose d'extérieur.