Entiendo lo que es una mónada. ¿Por qué necesitamos mónadas en Haskell? ¿Por qué es tan útil e importante?

Las mónadas son útiles en cualquier idioma. Haskell los utiliza mucho para eliminar repeticiones. Vea cómo Haskell usó Monads para eliminar el código repetitivo para manejar fallas en un cálculo, por ejemplo.

En Haskell tenemos un tipo Quizás que modela cálculos que pueden fallar. En Java solo usa un puntero nulo que puede pertenecer a cualquier tipo. Esto significa que el verificador de tipo no tiene idea de si tiene el potencial de devolver un puntero nulo o no. Como resultado, estos punteros nulos tienden a desmarcarse y, por lo tanto, la excepción de puntero nulo es un problema extremadamente común en Java. Lo mismo ocurre en Python con nulo y Perl con undef. C generalmente solo hace algo como return -1, que en realidad es un miembro válido del tipo y, por lo tanto, puede provocar errores en la lógica que nunca causan un bloqueo. Idiomas como Haskell y ML adoptan un enfoque más basado en principios y reflejan esta falla potencial en el tipo.

Verifique el tipo de la función de búsqueda.

lookup :: Eq a => a -> [(a,b)] -> Maybe b

Esto significa que toma una clave, una lista asociativa, y tal vez devuelve el valor asociado con esa clave. Sin embargo, podría no devolver nada si no hay ningún valor asociado con esa clave.

¿Qué sucede si quisiera agregar los valores asociados con tres de las claves?

addThreeValues1 :: (Eq a, Num b) => a -> a -> a -> [(a, b)] -> Quizás b
addThreeValues1 k1 k2 k3 assoc =
búsqueda de caso k1 asociación de
Nada -> nada
Solo v1 -> búsqueda de caso k2 asociación de
Nada -> nada
Solo v2 -> caso de búsqueda k3 asociación de
Nada -> nada
Just v3 -> Just (v1 + v2 + v3)

Observe cómo estamos repitiendo este patrón del bloque de casos una y otra vez y tenemos que verificar explícitamente Nada y devolver Nada cada vez que vemos obtener Nada. Esto es realmente molesto. Entonces, podría preguntarse, ¿se ve obligado a verificar explícitamente los errores cada vez que llama a una función que puede fallar una mala idea? Ciertamente parece innecesariamente complicar el código. Bueno, no si tienes la Mónada tal vez.

addThreeValues2 :: (Eq a, Num b) => a -> a -> a -> [(a, b)] -> Quizás b
addThreeValues2 k1 k2 k3 assoc = do
v1 <- búsqueda k1 assoc
v2 <- búsqueda k2 assoc
v3 <- búsqueda k3 assoc
Solo (v1 + v2 + v3)

Aquí tenemos lo mejor de ambos mundos. Excepciones comprobadas explícitamente sin todo el código repetitivo.

Hay muchos más ejemplos de esto. Intente escribir código puro que calcule valores aleatorios pasando el generador de números aleatorios explícitamente y luego revise la mónada Rand. Es exactamente el mismo tipo de beneficio.

Estas son dos preguntas no totalmente ajenas. La primera es la más fácil: necesitamos mónadas en Haskell para controlar los cálculos impuros. Esto se hace en el IO Monad incorporado. Por ejemplo, Clean (un poco como Haskell) tiene tipos únicos para controlar los cálculos potencialmente impuros, de modo que no necesita mónadas para eso. Pero Clean tiene mónadas. ¿Porqué entonces?

Bueno, como algunas personas señalan, las mónadas con su sintaxis do pueden ser útiles para construir programas agradables, manejando todo tipo de detalles esenciales para que su código sea más claro. Cualquier cosa que haga que los programas sean más legibles es útil.

Por ejemplo, mis alumnos a menudo necesitan implementar un análisis estático como un sistema de tipos. La forma más sencilla es realizar una sustitución a lo largo del análisis estático, actualizándola en el camino. Si escribe esto sin mónadas, se pierde rápidamente en toda la sustitución que fluye. Si oculta la sustitución en una mónada estatal, el código se vuelve mucho más limpio y tampoco puede olvidar accidentalmente una sustitución.

Jur

Si no comprende por qué las mónadas son tan útiles e importantes, entonces realmente no comprende qué es una mónada. Una mónada es una abstracción , una forma de ver las cosas desde un nivel superior sin atascarse en los detalles. Es una abstracción que abarca una fracción sorprendentemente grande de los tipos de cálculos que queremos realizar, y lo hace de una manera simple y uniforme.

Sin embargo, no te preocupes. Desarrollar una verdadera comprensión de las mónadas es un trabajo duro y lleva mucho tiempo (años, para la mayoría de las personas). Solo sigue pensando en ellos y usándolos, y eventualmente hará clic.

Digamos que desea representar un cálculo con estado, en un lenguaje puro sin efectos. Puede hacerlo escribiendo una función que tome un estado de entrada y calcule un resultado junto con un estado de salida. De esta manera, puede volver a alimentar el estado de salida en la misma función y “continuar” como si estuviera cambiando el estado a través de invocaciones.

Esto está bien y puede hacerse en cualquier idioma, incluso en matemáticas. Donde te encuentras con problemas es en la gestión de todo ese estado que pasa. Una vez que se involucran varias funciones, se vuelve complicado enhebrar el estado correctamente a través de todas ellas. ¿Qué pasa si reutilizas el estado incorrecto? ¿Qué pasa si olvidas pasar el nuevo estado?

¿No sería bueno si pudieras abstraer el paso del estado y enfocarte solo en las funciones subyacentes: si tuvieras una forma de hacer que el “paso del estado” sea parte del * significado de la composición *, para poder componer funciones con estado tal como podría componer funciones ordinarias, y todo el paso del estado sucedería, correctamente, detrás de escena.

Este tipo de abstracción es capturada por el concepto de “mónada”. Además es útil para muchas otras cosas, pero esta es una forma bastante común de encontrarlo.

Por último, si piensa en los “efectos sobre el medio ambiente” como un sabor de estado, le brinda una manera de pensar en E / S como la creación de un conjunto de instrucciones para que un tiempo de ejecución externo actúe sobre ellas. Esto no transmite la imagen completa de lo que hace Haskell (por ejemplo, no explica en absoluto las excepciones asincrónicas), pero tampoco es completamente falso.

Haskell es un lenguaje funcional “puro”. Las funciones no tienen efectos secundarios. Debido a la ausencia de efectos secundarios, la impresión sería imposible. Una mónada permite salir del mundo de la función pura para hacer algunas cosas “prácticas” orientadas al ser humano.