Una cosa que lo hace confuso es que las funciones "populares" les gusta bind
y <*>
están orientadas a la praxis. Pero para comprender los conceptos es más fácil observar otras funciones primero. También vale la pena señalar que las mónadas se destacan porque están un poco sobrevaloradas en comparación con otros conceptos conectados. Así que comenzaré con functors en su lugar.
Los functores ofrecen una función (en notación Haskell) fmap :: (Functor f) => (a -> b) -> f a -> f b
. En otras palabras, tiene un contexto en el f
que puede levantar una función. Como puedes imaginar, casi cualquier cosa es un functor. Listas, Quizás, Cualquiera, funciones, E / S, tuplas, analizadores ... Cada uno representa un contexto en el que puede aparecer un valor. Por lo tanto, puede escribir funciones extremadamente versátiles que funcionan en casi cualquier contexto utilizando fmap
o su variante en línea <$>
.
¿Qué otras cosas quieres hacer con los contextos? Es posible que desee combinar dos contextos. Así que es posible que desee obtener una generalización de zip :: [a] -> [b] -> [(a,b)]
, por ejemplo, así: pair :: (Monoidal f) => f a -> f b -> f (a,b)
.
Pero debido a que es aún más útil en la práctica, las bibliotecas de Haskell en su lugar ofrecen Applicative
, que es una combinación de Functor
y Monoidal
, y también de Unit
, que simplemente agrega que realmente puede poner valores "dentro" de su contexto unit
.
Puede escribir funciones extremadamente genéricas simplemente indicando estas tres cosas sobre el contexto en el que está trabajando.
Monad
es solo otra cosa que puedes decir sobre eso. Lo que no mencioné antes es que ya tiene dos formas de combinar dos contextos: no solo puede combinarlos pair
, sino que también puede apilarlos, por ejemplo, puede tener una lista de listas. En el contexto de E / S, un ejemplo sería una acción de E / S que puede leer otras acciones de E / S de un archivo, por lo que tendría un tipo FilePath -> IO (IO a)
. ¿Cómo podemos deshacernos de ese apilamiento para obtener una función ejecutable IO a
? Ahí es donde entra Monad
s join
, nos permite combinar dos contextos apilados del mismo tipo. Lo mismo ocurre con los analizadores sintácticos, Quizás, etc. Y bind
es solo una forma más práctica de usarjoin
Entonces, un contexto monádico solo tiene que ofrecer cuatro cosas y puede usarse con casi toda la maquinaria desarrollada para E / S, para analizadores, para fallas, etc.