Una regla práctica útil es cuando vea los valores en un contexto; mónadas pueden ser vistos como capas de "efectos" en:
- Tal vez: parcialidad (utiliza: cálculos que pueden fallar)
- O: errores de cortocircuito (usos: gestión de errores/excepción)
- [] (la mónada lista): no determinismo (utiliza: la generación de listas, filtrado, ...)
- Estado: una sola referencia mutable (utiliza: estado)
- Lector: un entorno compartido (utiliza: asociaciones de variables, información común, ...)
- escritor: un "canal lateral" de salida o de acumulación (utiliza: la explotación forestal, el mantenimiento de un contador de sólo escritura, ...)
- Cont: de control de flujo no local (usos: demasiado numerosas para enumerarlas)
por lo general, por lo general, debe diseñar su mónada por capas en los transformadores monad de la norma Monad Transformer Library, que te permiten combinar los efectos anteriores en un solo mo nad. Juntos, estos manejan la mayoría de las mónadas que podría querer usar. Hay algunas mónadas adicionales no incluidas en el MTL, como las mónadas probability y supply.
En cuanto a desarrollar una intuición para si un tipo definido recientemente es una mónada, y cómo se comporta como una sola, se puede pensar en él subiendo Functor
-Monad
:
- Functor te permite transformar valores con funciones puras.
- Aplicable le permite incrustar valores puros y la aplicación expresa -
(<*>)
le permite pasar de una función incrustada y su argumento incrustado a un resultado incrustado.
- Monad permite que la estructura de los cálculos integrados dependa de los valores de cálculos anteriores.
La forma más fácil de entender esto es mirar el tipo de join
:
join :: (Monad m) => m (m a) -> m a
Esto significa que si usted tiene un cálculo incrustado cuyo resultado es un nuevo cómputo embebido , puede crear un cálculo que ejecuta el resultado de ese cálculo. De modo que puede usar efectos monádicos para crear un nuevo cálculo basado en valores de cómputos previos, y transferir el flujo de control a ese cálculo.
Curiosamente, esto puede ser una debilidad de estructuración cosas monádicamente: con Applicative
, la estructura de la computación es estática (es decir, un determinado Applicative
cálculo tiene una cierta estructura de efectos que no pueden cambiar en función de los valores intermedios), mientras con Monad
es dinámico. Esto puede restringir la optimización que puede hacer; por ejemplo, los analizadores aplicativos son menos poderosos que los monádicos (bueno, esto no es strictly true, pero lo es efectivamente), pero se pueden optimizar mejor.
Tenga en cuenta que (>>=)
se puede definir como
m >>= f = join (fmap f m)
y así una mónada se puede definir simplemente con return
y join
(asumiendo que es un Functor
; todas las mónadas son funtores aplicativos, pero jerarquía de clase de tipos de Haskell por desgracia no lo hace requiere esto para historical reasons).
Como nota adicional, es probable que no deba centrarse demasiado en las mónadas, sin importar qué tipo de zumbido reciban de los no Haskellers equivocados. Hay muchas clases de tipos que representan patrones significativos y potentes, y no todo se expresa mejor como una mónada. Applicative, Monoid, Foldable ... qué abstracción usar depende completamente de su situación. Y, por supuesto, el hecho de que algo sea una mónada no significa que no pueda ser otras cosas también; ser una mónada es solo otra propiedad de un tipo.
Por lo tanto, no debe pensar demasiado acerca de "identificar mónadas"; las preguntas son más como:
- ¿Se puede expresar este código en una forma monádica más simple? ¿Con qué mónada?
- ¿Este tipo acabo de definir una mónada? ¿Qué patrones genéricos codificados por las funciones estándar en mónadas puedo aprovechar?
Es menos "este problema debería resolverse Monadically", y más "este problema debería resolverse con [algún tipo de datos], y ¡qué conveniente !, [ese tipo de datos] es una instancia de Monad, que me da toneladas de capacidad de compilación para trabajar ". –
@DanBurton: Lo cual es, por supuesto, de la misma forma en que se aplica cualquier otro tipo de patrón de diseño, ya sea en una lógica orientada a objetos, de procedimientos, funcional, de retroceso, concatenada o de cualquier otro tipo. –