Rápidamente nos podemos percatar de la importancia de los acentos!
Una mónada es una estructura algebraica en la teoría de categorías, y en Haskell se usa para describir cálculos como secuencias de pasos y para manejar efectos secundarios como estado de entrada o salida.
Las mónadas son abstractas y tienen muchos ejemplos concretos útiles.
Las mónadas proporcionan una forma de estructurar un programa.
Se pueden usar (junto con tipos de datos abstractos) para permitir que las acciones (por ejemplo, variables mutables) se implementen de forma segura.
Una mónada tiene tres bloques de construcción:
- Un constructor de tipos que produce el tipo de cálculo, dado el tipo de resultado de ese cálculo.
- Una función que toma un valor y devuelve un cálculo que, cuando se ejecuta, producirá ese valor.
- Una función que toma dos cálculos y los realiza uno tras otro, haciendo que el resultado del primer cálculo esté disponible para el segundo.
Una mónada consta de tres objetos, que deben satisfacer las leyes de la mónada. Veamos primero los objetos:
Un constructor de tipo M, tal que para cualquier tipo a, el tipo M a es el tipo de cálculo en la mónada M que produce un resultado de tipo a.
Una función return :: a → M a. Por lo tanto, si x :: a, return x es un cálculo en M que, cuando se ejecuta, producirá un valor de tipo a.
Una función (>> =) :: M a → (a → M b) → M b.
El primer argumento es un cálculo que produce un valor de tipo a.
El segundo argumento es una función que requiere un argumento de tipo a y devuelve un cálculo que produce un valor de tipo b.
Las leyes de las mónadas es un cálculo que producirá un valor de tipo b. Funciona ejecutando el primer cálculo y pasando su resultado a la función que devuelve el segundo cálculo, que luego se ejecuta.
Las mónadas son abstractas, generales y útiles.
En consecuencia, hay muchos casos de ellos.
Esto se captura mediante la definición de una clase de tipo para las mónadas, junto con muchas instancias estándar.
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
fail :: String -> m a
La función de retorno toma un valor y devuelve un valor monádico, es decir, un valor envuelto en el constructor de tipo monada.
El operador >> = (pronunciado "bind") es una parte crucial de una mónada. Vincula un valor devuelto de un cálculo a otro cálculo.
El operador >> (pronunciado "then") es como >> =, pero simplemente ignora el valor devuelto por el cálculo:
m >> n = m >> = \ _ -> n
El sistema utiliza la función de error para ayudar a producir mensajes de error cuando hay un patrón que no coincide; normalmente no lo usa directamente.
Cada mónada debe satisfacer las siguientes tres leyes. Entonces, si algo parece una mónada pero no satisface estas leyes, ¡no es una mónada! Las leyes expresan propiedades que deben satisfacerse para hacer componibles los cálculos monádicos.
La ley de unidad correcta:
m >> = retorno = m
La ley de la unidad izquierda:
devuelve x >> = f = f x
La ley de asociatividad:
(m >> = f) >> = g = m >> = (\ x -> f x >> = g)
Hay muchas metáforas o intuiciones sobre lo que es una mónada.
Ejemplo: un "cálculo" o una "acción". Pero estos términos son vagos: pueden ayudarlo a comprender, pero a veces también pueden ser engañosos.
Una mónada es exactamente lo que dice la definición, ni más ni menos.
Escribir cálculos monádicos usando los operadores bind y then sigue siendo algo torpe. Haskell proporciona un azúcar sintáctico muy conveniente para cálculos monádicos llamado "notación do":
baz :: [a] -> Maybe a
baz xs =
do a <- myTail xs
b <- myTail a
c <- myHead b
return c
Reglas de sintaxis para hacer
do { x } -- > x
do {x ; <xs> } -- > x >> do { <xs> }
do { a <- x ; <xs> } -- > x >>= \a -> do { <xs> }
do { let <declarations> ; xs } -- > let <declarations> in do { xs }