2012-01-08 16 views
40

Mi manera de aprender Haskell Empiezo a comprender el concepto de la mónada y empiezo a utilizar las mónadas conocidas en mi código, pero todavía tengo dificultades para acercarme a las mónadas desde el punto de vista del diseñador. En OO hay varias reglas como, "identificar sustantivos" para objetos, observar algún tipo de estado e interfaz ... pero no puedo encontrar recursos equivalentes para mónadas.¿Cómo identifica los patrones de diseño monádico?

Entonces, ¿cómo identifica un problema como de naturaleza monádica? ¿Cuáles son los buenos patrones de diseño para el diseño monádico? ¿Cuál es su enfoque cuando se da cuenta de que algún código sería mejor refactorizado en una mónada?

+8

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 ". –

+0

@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. –

Respuesta

57

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?
+3

Oh, muy agradable. Casi la respuesta que habría escrito si no hubiera estado durmiendo, jaja. Hombre, apenas puedo seguirles el paso a ustedes chicos ... –

+3

@ C.A.McCann: ¿Cómo pueden dormir cuando se gana un representante? :) – ehird

+0

@ehird +1 has estado generando toneladas de respuestas excelentes últimamente. –

15

Siga los tipos.

Si usted encuentra que usted ha escrito funciones con todos estos tipos

  • (a -> b) -> YourType a -> YourType b
  • a -> YourType a
  • YourType (YourType a) -> YourType a

o todos estos tipos

  • a -> YourType a
  • YourType a -> (a -> YourType b) -> YourType b

entonces YourTypepuede ser una mónada. (Digo “puede” porque las funciones deben obedecer las leyes de las mónadas también.)

(recuerde que puede reordenar los argumentos, por lo que por ejemplo YourType a -> (a -> b) -> YourType b es sólo (a -> b) -> YourType a -> YourType b disfrazada.)

no se ven a cabo sólo para Mónadas! Si tiene las funciones de todos estos tipos

  • YourType
  • YourType -> YourType -> YourType

y obedecen las leyes monoides, tiene un monoide! Eso también puede ser valioso. Del mismo modo para otras clases de tipos, lo más importante es Functor.

6

Ahí está el punto de vista efecto de mónadas:

  • Tal vez - la parcialidad/fallo de cortocircuito
  • O - error de información/cortocircuitos (como tal vez con más información)
  • escritor - Sólo escritura "Estado", comúnmente registro
  • Reader - read-only estado, comúnmente ambiente pasando
  • Estado - lectura/escritura estado
  • Reanudación - cómputo pausable
  • Lista - múltiples éxitos

Una vez que esté familiarizado con estos efectos es fácil de construir mónadas combinándolos con transformadores mónada. Tenga en cuenta que la combinación de algunas mónadas necesita cuidados especiales (particularmente Cont y cualquier mónada con retroceso).

Una cosa importante a tener en cuenta es que no hay muchas mónadas. Hay algunos exóticos que no están en las bibliotecas estándar, por ejemplo, la mónada de probabilidad y las variaciones de la mónada Cont como Codensity. Pero a menos que esté haciendo algo matemático, es poco probable que invente (o descubra) una nueva mónada, sin embargo, si usa Haskell el tiempo suficiente, construirá muchas mónadas que son combinaciones diferentes de las estándar.

Editar - Tenga en cuenta también que el orden se apilan transformadores resultados monad en diferentes mónadas:

Si agrega ErrorT (transformador) a una mónada escritor, se obtiene esta mónada Either err (log,a) - sólo se puede acceder al registro de si no tener ningún error

Si agrega WriterT (transfomer) a una mónada Error, obtendrá esta mónada (log, Either err a) que siempre da acceso al registro.

4

Esto es una especie de falta de respuesta, pero creo que es importante decirlo de todos modos. ¡Solo pregunte! StackOverflow,/r/haskell, y el canal #haskell irc son todos excelentes lugares para obtener comentarios rápidos de personas inteligentes. Si estás trabajando en un problema y sospechas que hay algo de magia monádica que podría facilitarlo, ¡solo pregúntaselo! La comunidad Haskell ama resolver problemas y es ridículamente amigable.

No malinterprete, no lo aliento a que nunca aprenda por usted mismo. Por el contrario, interactuar con la comunidad de Haskell es una de las mejores formas de aprender . LYAH y RWH, 2 libros de Haskell que están disponibles gratuitamente en línea, también son muy recomendables.

Ah, y no se olvide de jugar, jugar, jugar! Mientras juegas con el código monádico, comenzarás a tener la sensación de lo que tienen las mónadas de "forma", y cuando los combinadores monádicos pueden ser útiles. Si está moviendo su propia mónada, generalmente el sistema de tipos lo guiará a una solución obvia y simple. Pero para ser honesto, rara vez debería necesitar rodar su propia instancia de Monad, ya que las bibliotecas de Haskell proporcionan toneladas de cosas útiles, tal como lo mencionaron otros encuestados.