En règle générale, c'est quand vous voyez des valeurs dans un contexte; monades peut être vu comme la superposition des "effets" sur:
-
Peut-être: la partialité (utilise: calculs qui peuvent échouer)
-
Soit: court-circuit des erreurs (utilise: erreur/exception)
-
[] (la liste monade): non-déterminisme (utilise: la génération de liste, filtrage, ...)
-
État: un seul mutable référence (utilise: état)
-
Lecteur: un environnement partagé (utilise: variable, fixations, commune d'information, ...)
-
Écrivain: un "canal latéral" de la sortie ou de l'accumulation (utilise: enregistrement, le maintien d'une écriture seule compteur, ...)
-
Cont: non-local de flux de contrôle (utilise: trop nombreux pour être énumérés)
Habituellement, vous devez généralement la conception de votre monade par superposition sur la monade transformateurs de la norme Monade Transformateur de la Bibliothèque, qui vous permettent de combiner les effets ci-dessus en une seule monade. Ensemble, ils gèrent la majorité des monades vous souhaitez utiliser. Il y a quelques autres monades pas inclus dans la MTL, tels que la probabilité et de l'approvisionnement des monades.
Aussi loin que l'élaboration d'une intuition pour savoir si une nouvelle définition de type est une monade, et comment il se comporte comme un seul, vous pouvez penser à elle en remontant de Functor
de Monad
:
-
Foncteur vous permet de transformer des valeurs avec des fonctions pures.
-
Applicative permet d'intégrer pur valeurs et à la demande expresse -
(<*>)
vous permet de passer d'une fonction intégrée et embarqué argument intégré à la suite.
-
Monade permet à la structure intégrée de calculs dépendent des valeurs des calculs précédents.
La meilleure façon de comprendre cela est de regarder le type d' join
:
join :: (Monad m) => m (m a) -> m a
Cela signifie que si vous avez intégré de calcul dont le résultat est une nouvelle intégré de calcul, vous pouvez créer un calcul qui exécute le résultat de ce calcul. Ainsi, vous pouvez utiliser monadique effets pour créer un nouveau calcul fondé sur les valeurs de calculs précédents, et de transfert de flux de contrôle pour que le calcul.
Fait intéressant, cela peut être une faiblesse de la structuration des choses monadically: avec Applicative
, la structure du calcul est statique (c'est à dire un Applicative
calcul a une certaine structure, des effets qui ne peuvent changer en fonction des valeurs intermédiaires), alors qu'avec Monad
il est dynamique. Cela peut limiter l'optimisation que vous pouvez faire; par exemple, applicative analyseurs sont moins puissants que monadique (le bien, ce n'est pas strictement vrai, mais il est effectivement), mais ils peuvent être optimisés mieux.
Notez que (>>=)
peut être définie comme
m >>= f = join (fmap f m)
et donc, une monade peut être défini simplement avec de l' return
et join
(en supposant que c'est un Functor
; toutes les monades sont des foncteurs applicatifs, mais Haskell typeclass hiérarchie, malheureusement, n'a pas besoin de ce pour des raisons historiques).
Comme une note supplémentaire, vous ne devriez pas se concentrer trop sur les monades, peu importe quel genre de buzz qu'ils reçoivent de l'erronées de la non-Haskellers. Il y a beaucoup de typeclasses qui représentent significatif et puissant des modèles, et non pas tout ce qui a le mieux exprimé comme une monade. Applicative, Monoïde, Pliable... qui d'abstraction à utiliser dépend entièrement de votre situation. Et, bien sûr, juste parce que quelque chose est une monade ne veut pas dire qu'il ne peut pas être d'autres choses aussi; le fait d'être une monade est juste une autre propriété d'un type.
Donc, vous ne devriez pas trop penser à "l'identification des monades"; les questions sont plus du genre:
- Peut ce code sera exprimé plus simple monadique forme? Avec qui monade?
- C'est ce type que j'ai donc défini une monade? Que des modèles génériques codées par les fonctions standard sur les monades puis-je profiter de la?