Habiendo mirado brevemente a Haskell recientemente, ¿cuál sería un explicación breve, sucinta y práctica de lo que esencialmente es una mónada?
La mayoría de las explicaciones que he encontrado son bastante inaccesibles y carecen de detalles prácticos.
haskell
functional-programming
monads
terminology
Peter Mortensen
fuente
fuente
Respuestas:
Primero: el término mónada es un poco vacío si no eres matemático. Un término alternativo es generador de cómputo, que es un poco más descriptivo de para qué son realmente útiles.
Pides ejemplos prácticos:
Ejemplo 1: comprensión de la lista :
Esta expresión devuelve los dobles de todos los números impares en el rango de 1 a 10. ¡Muy útil!
Resulta que esto es solo azúcar sintáctico para algunas operaciones dentro de la mónada List. La misma lista de comprensión se puede escribir como:
O incluso:
Ejemplo 2: Entrada / Salida :
Ambos ejemplos usan mónadas, constructores de cálculo AKA. El tema común es que la mónada encadena las operaciones de alguna manera específica y útil. En la comprensión de la lista, las operaciones se encadenan de tal manera que si una operación devuelve una lista, las siguientes operaciones se realizan en cada elemento de la lista. Por otro lado, la mónada IO realiza las operaciones secuencialmente, pero pasa una "variable oculta", que representa "el estado del mundo", que nos permite escribir código de E / S de una manera puramente funcional.
Resulta que el patrón de operaciones de encadenamiento es bastante útil y se usa para muchas cosas diferentes en Haskell.
Otro ejemplo son las excepciones: al usar la
Error
mónada, las operaciones se encadenan de tal manera que se realizan de forma secuencial, excepto si se produce un error, en cuyo caso se abandona el resto de la cadena.Tanto la sintaxis de comprensión de lista como la notación de do son azúcar sintáctica para encadenar operaciones utilizando el
>>=
operador. Una mónada es básicamente solo un tipo que admite el>>=
operador.Ejemplo 3: un analizador sintáctico
Este es un analizador muy simple que analiza una cadena entre comillas o un número:
Las operaciones
char
,digit
etc. son bastante simples. O coinciden o no coinciden. La magia es la mónada que gestiona el flujo de control: las operaciones se realizan de forma secuencial hasta que falla una coincidencia, en cuyo caso la mónada retrocede a la última<|>
y prueba la siguiente opción. Una vez más, una forma de encadenar operaciones con algunas semánticas adicionales útiles.Ejemplo 4: programación asincrónica
Los ejemplos anteriores están en Haskell, pero resulta que F # también admite mónadas. Este ejemplo es robado de Don Syme :
Este método busca una página web. El uso de la línea de perforación es
GetResponseAsync
: realmente espera la respuesta en un hilo separado, mientras que el hilo principal regresa de la función. Las últimas tres líneas se ejecutan en el hilo generado cuando se ha recibido la respuesta.En la mayoría de los otros idiomas, tendría que crear explícitamente una función separada para las líneas que manejan la respuesta. La
async
mónada puede "dividir" el bloque por sí sola y posponer la ejecución de la segunda mitad. (Laasync {}
sintaxis indica que el flujo de control en el bloque está definido por laasync
mónada).Cómo trabajan ellos
Entonces, ¿cómo puede una mónada hacer todas estas cosas elegantes de flujo de control? Lo que realmente sucede en un do-block (o una expresión de cálculo como se los llama en F #), es que cada operación (básicamente cada línea) está envuelta en una función anónima separada. Estas funciones se combinan utilizando el
bind
operador (escrito>>=
en Haskell). Dado que labind
operación combina funciones, puede ejecutarlas como mejor le parezca: secuencialmente, varias veces, a la inversa, descarte algunas, ejecute algunas en un hilo separado cuando lo desee, etc.Como ejemplo, esta es la versión ampliada del código IO del ejemplo 2:
Esto es más feo, pero también es más obvio lo que realmente está sucediendo. El
>>=
operador es el ingrediente mágico: toma un valor (en el lado izquierdo) y lo combina con una función (en el lado derecho), para producir un nuevo valor. Este nuevo valor es tomado por el siguiente>>=
operador y nuevamente combinado con una función para producir un nuevo valor.>>=
puede ser visto como un mini evaluador.Tenga en cuenta que
>>=
está sobrecargado para diferentes tipos, por lo que cada mónada tiene su propia implementación de>>=
. (Sin embargo, todas las operaciones en la cadena deben ser del tipo de la misma mónada; de lo contrario, el>>=
operador no funcionará).La implementación más simple posible de
>>=
simplemente toma el valor a la izquierda y lo aplica a la función a la derecha y devuelve el resultado, pero como se dijo antes, lo que hace que todo el patrón sea útil es cuando hay algo extra en la implementación de la mónada de>>=
.Existe cierta inteligencia adicional en cómo se pasan los valores de una operación a la siguiente, pero esto requiere una explicación más profunda del sistema de tipo Haskell.
Resumiendo
En términos de Haskell, una mónada es un tipo parametrizado que es una instancia de la clase de tipo Mónada, que define
>>=
junto con algunos otros operadores. En términos simples, una mónada es solo un tipo para el que>>=
se define la operación.En sí mismo
>>=
es solo una forma engorrosa de encadenar funciones, pero con la presencia de la notación que oculta la "fontanería", las operaciones monádicas resultan ser una abstracción muy agradable y útil, útil en muchos lugares del lenguaje y útil. para crear tus propios mini idiomas en el idioma.¿Por qué son duras las mónadas?
Para muchos estudiantes de Haskell, las mónadas son un obstáculo que golpean como una pared de ladrillos. No es que las mónadas en sí mismas sean complejas, sino que la implementación se basa en muchas otras características avanzadas de Haskell como tipos parametrizados, clases de tipos, etc. El problema es que Haskell I / O se basa en mónadas, y I / O es probablemente una de las primeras cosas que desea comprender al aprender un nuevo idioma; después de todo, no es muy divertido crear programas que no producen salida. No tengo una solución inmediata para este problema de huevo y gallina, excepto tratar la E / S como "la magia sucede aquí" hasta que tenga suficiente experiencia con otras partes del lenguaje. Lo siento.
Excelente blog sobre mónadas: http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
fuente
Explicar "¿Qué es una mónada?" Es un poco como decir "¿Qué es un número?" Usamos números todo el tiempo. Pero imagina que conociste a alguien que no sabía nada sobre números. ¿Cómo diablos explicarías qué son los números? ¿Y cómo comenzarías a describir por qué eso podría ser útil?
¿Qué es una mónada? La respuesta corta: es una forma específica de encadenar operaciones juntas.
En esencia, está escribiendo pasos de ejecución y vinculándolos con la "función de enlace". (En Haskell, se llama así
>>=
). Puede escribir las llamadas al operador de enlace usted mismo, o puede usar la sintaxis sugar que hace que el compilador inserte esas llamadas de función por usted. Pero de cualquier manera, cada paso está separado por una llamada a esta función de enlace.Entonces la función de enlace es como un punto y coma; Separa los pasos en un proceso. El trabajo de la función de vinculación es tomar la salida del paso anterior y pasarla al siguiente paso.
Eso no suena demasiado difícil, ¿verdad? Pero hay más de un tipo de mónada. ¿Por qué? ¿Cómo?
Bueno, la función de vinculación solo puede tomar el resultado de un paso y pasarlo al siguiente. Pero si eso es "todo" que hace la mónada ... eso en realidad no es muy útil. Y eso es importante de entender: cada mónada útil hace algo más además de ser una mónada. Cada mónada útil tiene un "poder especial", que lo hace único.
(Una mónada que no hace nada especial se llama "mónada de identidad". Más bien como la función de identidad, esto suena como algo completamente inútil, pero resulta que no es ... Pero esa es otra historia ™).
Básicamente, cada mónada tiene su propia implementación de la función de vinculación. Y puede escribir una función de enlace de modo que haga cosas entre los pasos de ejecución. Por ejemplo:
Si cada paso devuelve un indicador de éxito / fracaso, puede hacer que Bind ejecute el siguiente paso solo si el anterior tuvo éxito. De esta manera, un paso fallido anula la secuencia completa "automáticamente", sin ninguna prueba condicional de su parte. (La falla Mónada .)
Extendiendo esta idea, puede implementar "excepciones". (La Mónada de Error o Mónada de Excepción ). Debido a que usted los define a usted mismo en lugar de ser una característica del lenguaje, puede definir cómo funcionan. (Por ejemplo, tal vez quieras ignorar las dos primeras excepciones y solo abortar cuando se lanza una tercera excepción).
Puede hacer que cada paso devuelva múltiples resultados , y hacer que la función de enlace se repita sobre ellos, alimentando cada uno en el siguiente paso para usted. De esta manera, no tiene que seguir escribiendo bucles por todas partes cuando se trata de múltiples resultados. La función de enlace "automáticamente" hace todo eso por usted. (La Lista Mónada ).
Además de pasar un "resultado" de un paso a otro, también puede hacer que la función de enlace pase datos adicionales . Estos datos ahora no aparecen en su código fuente, pero aún puede acceder a ellos desde cualquier lugar, sin tener que pasarlos manualmente a todas las funciones. (El lector Monad .)
Puede hacerlo para que se puedan reemplazar los "datos adicionales". Esto le permite simular actualizaciones destructivas , sin hacer actualizaciones destructivas. (La mónada estatal y su primo el escritor mónada ).
Debido a que solo está simulando actualizaciones destructivas, puede hacer cosas triviales que serían imposibles con actualizaciones destructivas reales . Por ejemplo, puede deshacer la última actualización o volver a una versión anterior .
Puede hacer una mónada donde los cálculos se pueden pausar , por lo que puede pausar su programa, entrar y jugar con los datos de estado internos, y luego reanudarlo.
Puede implementar "continuaciones" como una mónada. ¡Esto te permite romper las mentes de las personas!
Todo esto y más es posible con las mónadas. Por supuesto, todo esto también es perfectamente posible sin mónadas. Es drásticamente más fácil usar mónadas.
fuente
En realidad, contrario a la comprensión común de las mónadas, no tienen nada que ver con el estado. Las mónadas son simplemente una forma de envolver cosas y proporcionar métodos para realizar operaciones en las cosas envueltas sin desenvolverlas.
Por ejemplo, puede crear un tipo para envolver otro, en Haskell:
Para envolver cosas definimos
Para realizar operaciones sin desenvolver, digamos que tiene una función
f :: a -> b
, luego puede hacer esto para levantar esa función para actuar sobre valores envueltos:Eso es todo lo que hay que entender. Sin embargo, resulta que hay una función más general para hacer este levantamiento , que es
bind
:bind
puede hacer un poco más quefmap
, pero no al revés. En realidad, solofmap
se puede definir en términos debind
yreturn
. Entonces, al definir una mónada ... le das su tipo (aquí estabaWrapped a
) y luego dices cómo esreturn
ybind
operaciones de trabajo.Lo bueno es que esto resulta ser un patrón tan general que aparece por todas partes, el estado de encapsulación de manera pura es solo uno de ellos.
Para un buen artículo sobre cómo se pueden usar las mónadas para introducir dependencias funcionales y así controlar el orden de evaluación, como se usa en la mónada IO de Haskell, consulte IO Inside .
En cuanto a la comprensión de las mónadas, no te preocupes demasiado por eso. Lea sobre ellos lo que le parezca interesante y no se preocupe si no entiende de inmediato. Entonces simplemente bucear en un idioma como Haskell es el camino a seguir. Las mónadas son una de estas cosas en las que la comprensión se infiltra en tu cerebro mediante la práctica, un día de repente te das cuenta de que las entiendes.
fuente
Pero, ¡podrías haber inventado mónadas!
fuente
Una mónada es un tipo de datos que tiene dos operaciones:
>>=
(akabind
) yreturn
(akaunit
).return
toma un valor arbitrario y crea una instancia de la mónada con él.>>=
toma una instancia de la mónada y asigna una función sobre ella. (Ya puede ver que una mónada es un tipo de datos extraño, ya que en la mayoría de los lenguajes de programación no se puede escribir una función que tome un valor arbitrario y cree un tipo a partir de ella. Las mónadas usan un tipo de polimorfismo paramétrico ).En notación Haskell, la interfaz de mónada está escrita
Se supone que estas operaciones obedecen ciertas "leyes", pero eso no es extremadamente importante: las "leyes" simplemente codifican la forma en que las implementaciones sensatas de las operaciones deberían comportarse (básicamente, eso
>>=
yreturn
deberían estar de acuerdo sobre cómo los valores se transforman en instancias de mónada y eso>>=
es asociativo).Las mónadas no son solo sobre estado y E / S: resumen un patrón común de cómputo que incluye trabajar con estado, E / S, excepciones y no determinismo. Probablemente las mónadas más simples de entender son las listas y los tipos de opciones:
donde
[]
y:
son los constructores de la lista,++
es el operador de concatenaciónJust
yNothing
son losMaybe
constructores. Ambas mónadas encapsulan patrones de cálculo comunes y útiles en sus respectivos tipos de datos (tenga en cuenta que ninguno tiene nada que ver con los efectos secundarios o E / S).Realmente tienes que jugar escribiendo un código Haskell no trivial para apreciar de qué se tratan las mónadas y por qué son útiles.
fuente
Primero debes entender qué es un functor. Antes de eso, comprenda las funciones de orden superior.
Una función de orden superior es simplemente una función que toma una función como argumento.
Un functor es cualquier construcción de tipo
T
para la que existe una función de orden superior, llamadamap
, que transforma una función de tipoa -> b
(dados dos tiposa
yb
) en una funciónT a -> T b
. Estamap
función también debe obedecer las leyes de identidad y composición de manera que las siguientes expresiones devuelvan verdaderas para todosp
yq
(notación Haskell):Por ejemplo, un constructor de tipo llamado
List
es un functor si viene equipado con una función de tipo(a -> b) -> List a -> List b
que obedece las leyes anteriores. La única implementación práctica es obvia. LaList a -> List b
función resultante itera sobre la lista dada, llamando a la(a -> b)
función para cada elemento y devuelve la lista de resultados.Una mónada es esencialmente sólo un funtor
T
con dos métodos adicionales,join
, de tipoT (T a) -> T a
, yunit
(a veces llamadoreturn
,fork
opure
) de tipoa -> T a
. Para listas en Haskell:¿Por qué es útil? Porque podría, por ejemplo,
map
sobre una lista con una función que devuelve una lista.Join
toma la lista resultante de listas y las concatena.List
es una mónada porque esto es posible.Puedes escribir una función que sí
map
, entoncesjoin
. Esta función se llamabind
, oflatMap
, o(>>=)
, o(=<<)
. Así es normalmente como se da una instancia de mónada en Haskell.Una mónada tiene que cumplir ciertas leyes, a saber, que
join
deben ser asociativas. Esto significa que si tiene un valorx
de tipo[[[a]]]
,join (join x)
debería ser igualjoin (map join x)
. Ypure
debe ser una identidad parajoin
esojoin (pure x) == x
.fuente
[Descargo de responsabilidad: todavía estoy tratando de asimilar por completo a las mónadas. Lo siguiente es justo lo que he entendido hasta ahora. Si está mal, espero que alguien con conocimiento me llame a la alfombra.]
Arnar escribió:
Eso es precisamente eso. La idea es así:
Tomas algún tipo de valor y lo envuelves con información adicional. Al igual que el valor es de cierto tipo (por ejemplo, un entero o una cadena), la información adicional es de cierto tipo.
Por ejemplo, esa información adicional podría ser una
Maybe
o unaIO
.Luego tiene algunos operadores que le permiten operar con los datos empaquetados mientras transporta esa información adicional. Estos operadores usan la información adicional para decidir cómo cambiar el comportamiento de la operación en el valor envuelto.
Por ejemplo, a
Maybe Int
puede ser aJust Int
oNothing
. Ahora, si agrega unMaybe Int
a aMaybe Int
, el operador verificará si ambos estánJust Int
dentro de s, y si es así, desenvolverá losInt
s, pasará el operador de suma, volverá a envolver el resultadoInt
en un nuevoJust Int
(que es válidoMaybe Int
) y, por lo tanto, devuelve aMaybe Int
. Pero si uno de ellos estabaNothing
dentro, este operador regresará inmediatamenteNothing
, lo que nuevamente es válidoMaybe Int
. De esa manera, puede fingir que susMaybe Int
números son solo números normales y realizar cálculos matemáticos regulares sobre ellos. Si tuviera que obtener unaNothing
, sus ecuaciones aún producirán el resultado correcto, sin que tenga que tirar cheques porNothing
todas partes .Pero el ejemplo es justo lo que sucede
Maybe
. Si la información adicional fuera unIO
, entoncesIO
se llamaría a ese operador especial definido para s, y podría hacer algo totalmente diferente antes de realizar la adición. (OK, agregar dosIO Int
s juntos probablemente no tenga sentido, aún no estoy seguro.) (Además, si prestó atención alMaybe
ejemplo, habrá notado que "envolver un valor con cosas adicionales" no siempre es correcto. Pero es difícil ser exacto, correcto y preciso sin ser inescrutable).Básicamente, "mónada" significa más o menos "patrón" . Pero en lugar de un libro lleno de Patrones explicados informalmente y específicamente nombrados, ahora tiene una construcción de lenguaje - sintaxis y todo - que le permite declarar nuevos patrones como elementos en su programa . (La imprecisión aquí es que todos los patrones tienen que seguir una forma particular, por lo que una mónada no es tan genérica como un patrón. Pero creo que ese es el término más cercano que la mayoría de la gente conoce y entiende).
Y es por eso que las personas encuentran a las mónadas tan confusas: porque son un concepto tan genérico. Preguntar qué hace que algo sea una mónada es igualmente vago como preguntar qué hace que algo sea un patrón.
Pero piense en las implicaciones de tener un soporte sintáctico en el lenguaje para la idea de un patrón: en lugar de tener que leer el libro Gang of Four y memorizar la construcción de un patrón en particular, simplemente escriba código que implemente este patrón de manera agnóstica, forma genérica una vez y ya está! Luego puede reutilizar este patrón, como Visitor o Strategy o Façade o lo que sea, simplemente decorando las operaciones en su código con él, ¡sin tener que volver a implementarlo una y otra vez!
Es por eso que las personas que entienden las mónadas las encuentran tan útiles. : no es un concepto de torre de marfil del que los snobs intelectuales se enorgullecen de comprender (OK, eso también, por supuesto, teehee), sino que en realidad simplifica el código.
fuente
M (M a) -> M a
. El hecho de que puede convertir eso en uno de tipoM a -> (a -> M b) -> M b
es lo que los hace útiles.Después de mucho esfuerzo, creo que finalmente entiendo la mónada. Después de releer mi larga crítica de la respuesta abrumadoramente votada, ofreceré esta explicación.
Hay tres preguntas que deben responderse para comprender las mónadas:
Como señalé en mis comentarios originales, demasiadas explicaciones de mónada quedan atrapadas en la pregunta número 3, sin, y antes de realmente cubrir adecuadamente la pregunta 2 o la pregunta 1.
¿Por qué necesitas una mónada?
Los lenguajes funcionales puros como Haskell son diferentes de los lenguajes imperativos como C o Java en que un programa funcional puro no se ejecuta necesariamente en un orden específico, un paso a la vez. Un programa Haskell es más parecido a una función matemática, en la que puede resolver la "ecuación" en cualquier número de órdenes potenciales. Esto confiere una serie de beneficios, entre los que se encuentra que elimina la posibilidad de ciertos tipos de errores, particularmente aquellos relacionados con cosas como "estado".
Sin embargo, hay ciertos problemas que no son tan fáciles de resolver con este estilo de programación. Algunas cosas, como la programación de la consola y la E / S de archivos, necesitan que las cosas sucedan en un orden particular, o necesitan mantener el estado. Una forma de abordar este problema es crear un tipo de objeto que represente el estado de un cálculo y una serie de funciones que toman un objeto de estado como entrada y devuelven un nuevo objeto de estado modificado.
Entonces, creemos un valor hipotético de "estado", que represente el estado de una pantalla de consola. exactamente cómo se construye este valor no es importante, pero digamos que es una matriz de caracteres ASCII de longitud de bytes que representa lo que está visible actualmente en la pantalla, y una matriz que representa la última línea de entrada ingresada por el usuario, en pseudocódigo. Hemos definido algunas funciones que toman el estado de la consola, la modifican y devuelven un nuevo estado de la consola.
Entonces, para hacer la programación de la consola, pero de una manera puramente funcional, necesitaría anidar muchas llamadas de función dentro de cada una.
La programación de esta manera mantiene el estilo funcional "puro", al tiempo que obliga a que se realicen cambios en la consola en un orden particular. Pero probablemente querremos hacer más que unas pocas operaciones a la vez, como en el ejemplo anterior. Las funciones de anidamiento de esa manera comenzarán a ser torpes. Lo que queremos es un código que haga esencialmente lo mismo que el anterior, pero que esté escrito un poco más así:
De hecho, esta sería una forma más conveniente de escribirlo. ¿Cómo hacemos eso sin embargo?
¿Qué es una mónada?
Una vez que tenga un tipo (como
consolestate
) que defina junto con un conjunto de funciones diseñadas específicamente para operar en ese tipo, puede convertir todo el paquete de estas cosas en una "mónada" definiendo un operador como:
(vincular) que automáticamente alimenta los valores de retorno a su izquierda, a los parámetros de función a su derecha, y unlift
operador que convierte las funciones normales, en funciones que funcionan con ese tipo específico de operador de enlace.¿Cómo se implementa una mónada?
Vea otras respuestas, que parecen bastante libres para entrar en detalles.
fuente
Después de responder a esta pregunta hace unos años, creo que puedo mejorar y simplificar esa respuesta con ...
Una mónada es una técnica de composición de funciones que externaliza el tratamiento para algunos escenarios de entrada utilizando una función de composición,
bind
, para preprocesar la entrada durante la composición.En composición normal, la función,
compose (>>)
se usa para aplicar la función compuesta al resultado de su predecesor en secuencia. Es importante destacar que la función que se compone es necesaria para manejar todos los escenarios de su entrada.(x -> y) >> (y -> z)
Este diseño puede mejorarse mediante la reestructuración de la entrada para que los estados relevantes sean más fácilmente interrogados. Entonces, en lugar de simplemente
y
el valor puede convertirseMb
en, por ejemplo,(is_OK, b)
si sey
incluye una noción de validez.Por ejemplo, cuando la entrada es solamente posiblemente un número, en lugar de devolver una cadena que puede contener diligentemente contener un número o no, usted podría reestructurar el tipo en un
bool
indicando la presencia de un número válido y un número en tupla tal como,bool * float
. Las funciones compuestas ahora ya no necesitarían analizar una cadena de entrada para determinar si existe un número, sino que simplemente podrían inspeccionar labool
parte de una tupla.(Ma -> Mb) >> (Mb -> Mc)
Aquí, una vez más, la composición ocurre naturalmente con,
compose
por lo que cada función debe manejar todos los escenarios de su entrada individualmente, aunque hacerlo ahora es mucho más fácil.Sin embargo, ¿qué pasaría si pudiéramos externalizar el esfuerzo de interrogación para aquellos momentos en los que manejar un escenario es una rutina? Por ejemplo, ¿qué pasa si nuestro programa no hace nada cuando la entrada no está bien como en cuando lo
is_OK
estáfalse
? Si eso se hiciera, las funciones compuestas no tendrían que manejar ese escenario por sí mismas, simplificando drásticamente su código y logrando otro nivel de reutilización.Para lograr esta externalización podríamos usar una función
bind (>>=)
,, para realizar el encomposition
lugar decompose
. Como tal, en lugar de simplemente transferir valores de la salida de una función a la entrada de otraBind
, inspeccionaría laM
porciónMa
y decidiría si aplicar la función compuesta a la función compuesta y cómoa
. Por supuesto, la funciónbind
se definiría específicamente para nuestro particular aM
fin de poder inspeccionar su estructura y realizar cualquier tipo de aplicación que queramos. Sin embargo,a
puede ser cualquier cosa, ya quebind
simplemente pasa laa
inspeccionado a la función compuesta cuando determina la aplicación necesaria. Además, las funciones compuestas en sí mismas ya no necesitan lidiar conM
parte de la estructura de entrada tampoco, simplificándolas. Por lo tanto...(a -> Mb) >>= (b -> Mc)
o más sucintamenteMb >>= (b -> Mc)
En resumen, una mónada se externaliza y, por lo tanto, proporciona un comportamiento estándar alrededor del tratamiento de ciertos escenarios de entrada una vez que la entrada se diseña para exponerlos suficientemente. Este diseño es un
shell and content
modelo en el que el shell contiene datos relevantes para la aplicación de la función compuesta y es interrogado y solo está disponible para labind
función.Por lo tanto, una mónada es tres cosas:
M
caparazón para guardar información relevante de la mónada,bind
función implementada para hacer uso de esta información de shell en su aplicación de las funciones compuestas a los valores de contenido que encuentra dentro del shell, ya -> Mb
produciendo resultados que incluyen datos de gestión monádica.En términos generales, la entrada a una función es mucho más restrictiva que su salida, lo que puede incluir cosas como condiciones de error; por lo tanto, la
Mb
estructura de resultados es generalmente muy útil. Por ejemplo, el operador de división no devuelve un número cuando el divisor es0
.Además,
monad
s puede incluir funciones de ajuste que envuelven valores,a
en el tipo monádicoMa
, y funciones generalesa -> b
, en funciones monádicasa -> Mb
, ajustando sus resultados después de la aplicación. Por supuesto, comobind
, tales funciones de ajuste son específicas deM
. Un ejemplo:El diseño de la
bind
función supone estructuras de datos inmutables y funciones puras, otras cosas se vuelven complejas y no se pueden hacer garantías. Como tal, hay leyes monádicas:Dado...
Entonces...
Associativity
significa quebind
conserva el orden de evaluación independientemente de cuándobind
se aplique. Es decir, en la definición deAssociativity
arriba, la fuerza de la evaluación temprana del paréntesisbinding
def
yg
solo dará como resultado una función que se esperaMa
para completar elbind
. Por lo tanto, la evaluación deMa
debe determinarse antes de que su valor pueda aplicarsef
y ese resultado a su vez se apliqueg
.fuente
Una mónada es, efectivamente, una forma de "operador de tipo". Hará tres cosas. Primero "envolverá" (o convertirá) un valor de un tipo en otro tipo (típicamente llamado "tipo monádico"). En segundo lugar, hará que todas las operaciones (o funciones) estén disponibles en el tipo subyacente disponible en el tipo monádico. Finalmente proporcionará soporte para combinarse con otra mónada para producir una mónada compuesta.
La "quizás mónada" es esencialmente el equivalente de "tipos anulables" en Visual Basic / C #. Toma un tipo "T" no anulable y lo convierte en un "Nullable <T>", y luego define lo que significan todos los operadores binarios en un Nullable <T>.
Los efectos secundarios se representan de manera similar. Se crea una estructura que contiene descripciones de los efectos secundarios junto con el valor de retorno de una función. Las operaciones "levantadas" luego copian los efectos secundarios a medida que se pasan valores entre funciones.
Se llaman "mónadas" en lugar del nombre más fácil de entender de "operadores de tipo" por varias razones:
fuente
(Ver también las respuestas en ¿Qué es una mónada? )
¡Una buena motivación para las mónadas es sigfpe (Dan Piponi), ¡ Podrías haber inventado mónadas! (Y tal vez ya lo tengas) . Hay MUCHOS otros tutoriales de mónadas , muchos de los cuales tratan erróneamente de explicar las mónadas en "términos simples" usando varias analogías: esta es la falacia del tutorial de mónada ; Evítales.
Como dice DR MacIver en Cuéntanos por qué apesta tu idioma :
¿Dices que entiendes a la Mónada Quizás? Bien, ya estás en camino. Simplemente comience a usar otras mónadas y, tarde o temprano, comprenderá qué son las mónadas en general.
[Si está orientado matemáticamente, es posible que desee ignorar las docenas de tutoriales y aprender la definición, o seguir conferencias en teoría de categorías :) La parte principal de la definición es que una Mónada M involucra un "constructor de tipos" que define para cada tipo existente "T", un nuevo tipo "MT", y algunas formas de ir y venir entre tipos "normales" y tipos "M".]
Además, sorprendentemente, una de las mejores introducciones a las mónadas es en realidad uno de los primeros trabajos académicos que presenta a las mónadas, las mónadas de Philip Wadler para la programación funcional . En realidad, tiene ejemplos prácticos y no triviales de motivación, a diferencia de muchos de los tutoriales artificiales que existen.
fuente
Las mónadas deben controlar el flujo de los tipos de datos abstractos para los datos.
En otras palabras, muchos desarrolladores se sienten cómodos con la idea de conjuntos, listas, diccionarios (o hashes o mapas) y árboles. Dentro de esos tipos de datos hay muchos casos especiales (por ejemplo, InsertionOrderPreservingIdentityHashMap).
Sin embargo, cuando se enfrentan con el "flujo" del programa, muchos desarrolladores no han estado expuestos a muchas más construcciones que if, switch / case, do, while, goto (grr) y (quizás) cierres.
Entonces, una mónada es simplemente una construcción de flujo de control. Una mejor frase para reemplazar a la mónada sería 'tipo de control'.
Como tal, una mónada tiene ranuras para la lógica de control, o declaraciones o funciones: el equivalente en las estructuras de datos sería decir que algunas estructuras de datos le permiten agregar datos y eliminarlos.
Por ejemplo, la mónada "if":
en su forma más simple tiene dos espacios: una cláusula y un bloque. los
if
mónada generalmente se construye para evaluar el resultado de la cláusula y, si no es falso, evaluar el bloque. Muchos desarrolladores no son introducidos a las mónadas cuando aprenden 'si', y simplemente no es necesario entender a las mónadas para escribir una lógica efectiva.Las mónadas pueden volverse más complicadas, de la misma manera que las estructuras de datos pueden volverse más complicadas, pero hay muchas categorías amplias de mónadas que pueden tener una semántica similar, pero diferentes implementaciones y sintaxis.
Por supuesto, de la misma manera que las estructuras de datos pueden iterarse o atravesarse, pueden evaluarse las mónadas.
Los compiladores pueden o no tener soporte para mónadas definidas por el usuario. Haskell ciertamente lo hace. Ioke tiene algunas capacidades similares, aunque el término mónada no se usa en el lenguaje.
fuente
Mi tutorial favorito de Monad:
http://www.haskell.org/haskellwiki/All_About_Monads
(¡de 170,000 visitas en una búsqueda en Google de "mónada tutorial"!)
@Stu: El objetivo de las mónadas es permitirle agregar (generalmente) semántica secuencial a un código puro; incluso puede componer mónadas (usando Transformadores de mónada) y obtener una semántica combinada más interesante y complicada, como el análisis con manejo de errores, estado compartido y registro, por ejemplo. Todo esto es posible en código puro, las mónadas solo le permiten abstraerlo y reutilizarlo en bibliotecas modulares (siempre bueno en programación), así como proporcionar una sintaxis conveniente para que parezca imprescindible.
Haskell ya tiene una sobrecarga de operadores [1]: utiliza clases de tipos de la misma manera que uno podría usar interfaces en Java o C #, pero resulta que Haskell también permite tokens no alfanuméricos como + && y> como identificadores de infijo. Es solo sobrecarga del operador en su forma de verlo si quiere decir "sobrecargar el punto y coma" [2]. Suena como magia negra y pide problemas para "sobrecargar el punto y coma" (los piratas informáticos emprendedores de Perl se enteran de esta idea) pero el punto es que sin mónadas no hay punto y coma, ya que el código puramente funcional no requiere ni permite una secuencia explícita.
Todo esto suena mucho más complicado de lo necesario. El artículo de sigfpe es bastante bueno, pero utiliza a Haskell para explicarlo, lo que no logra resolver el problema del huevo y la gallina de entender a Haskell para mimar a las mónadas y entender a las mónadas para que las mimeticen.
[1] Este es un problema separado de las mónadas, pero las mónadas utilizan la función de sobrecarga del operador de Haskell.
[2] Esto también es una simplificación excesiva ya que el operador para encadenar acciones monádicas es >> = (pronunciado "bind") pero hay un azúcar sintáctico ("do") que le permite usar llaves y puntos y comas y / o sangría y líneas nuevas.
fuente
He estado pensando en las mónadas de una manera diferente, últimamente. He estado pensando en ellos como abstrayendo el orden de ejecución de una manera matemática, lo que hace posible nuevos tipos de polimorfismo.
Si está utilizando un lenguaje imperativo y escribe algunas expresiones en orden, el código SIEMPRE se ejecuta exactamente en ese orden.
Y en el caso simple, cuando usa una mónada, se siente igual: define una lista de expresiones que suceden en orden. Excepto que, dependiendo de la mónada que use, su código podría ejecutarse en orden (como en la mónada IO), en paralelo sobre varios elementos a la vez (como en la mónada Lista), podría detenerse a la mitad (como en la mónada Quizás) , podría detenerse a medio camino para reanudarse más tarde (como en una mónada Reanudación), podría rebobinarse y comenzar desde el principio (como en una mónada de Transacción), o podría rebobinarse parcialmente para probar otras opciones (como en una mónada Lógica) .
Y debido a que las mónadas son polimórficas, es posible ejecutar el mismo código en diferentes mónadas, según sus necesidades.
Además, en algunos casos, es posible combinar mónadas (con transformadores de mónada) para obtener múltiples funciones al mismo tiempo.
fuente
Todavía soy nuevo en las mónadas, pero pensé que compartiría un enlace que encontré que se sintió realmente bien para leer (¡CON FOTOS!): Http://www.matusiak.eu/numerodix/blog/2012/3/11/ mónadas para el laico / (sin afiliación)
Básicamente, el concepto cálido y difuso que obtuve del artículo fue el concepto de que las mónadas son básicamente adaptadores que permiten que funciones dispares funcionen de una manera composable, es decir, ser capaz de agrupar múltiples funciones y mezclarlas y combinarlas sin preocuparse por un retorno inconsistente tipos y tal. Entonces, la función BIND se encarga de mantener las manzanas con manzanas y las naranjas con naranjas cuando intentamos hacer estos adaptadores. Y la función LIFT se encarga de tomar las funciones de "nivel inferior" y "actualizarlas" para que funcionen con las funciones BIND y también sean componibles.
Espero haberlo entendido bien y, lo que es más importante, espero que el artículo tenga una visión válida sobre las mónadas. Por lo menos, este artículo me ayudó a despertar mi apetito por aprender más sobre las mónadas.
fuente
Además de las excelentes respuestas anteriores, permítame ofrecerle un enlace al siguiente artículo (de Patrick Thomson) que explica las mónadas relacionando el concepto con la biblioteca JavaScript jQuery (y su forma de usar el "encadenamiento de métodos" para manipular el DOM) : jQuery es una mónada
La documentación de jQuery en sí misma no se refiere al término "mónada", sino que habla sobre el "patrón de construcción", que probablemente sea más familiar. Esto no cambia el hecho de que tienes una mónada adecuada allí, incluso sin darte cuenta.
fuente
Las mónadas no son metáforas , sino una abstracción prácticamente útil que emerge de un patrón común, como explica Daniel Spiewak.
fuente
Una mónada es una forma de combinar cálculos que comparten un contexto común. Es como construir una red de tuberías. Al construir la red, no fluyen datos a través de ella. Pero cuando he terminado de unir todos los bits con 'bind' y 'return', invoco algo así
runMyMonad monad data
y los datos fluyen a través de las tuberías.fuente
En la práctica, monad es una implementación personalizada del operador de composición de funciones que se encarga de los efectos secundarios y los valores de entrada y retorno incompatibles (para el encadenamiento).
fuente
Si he entendido correctamente, IEnumerable se deriva de mónadas. Me pregunto si ese podría ser un ángulo de enfoque interesante para aquellos de nosotros del mundo de C #.
Para lo que vale, aquí hay algunos enlaces a tutoriales que me ayudaron (y no, todavía no entiendo qué son las mónadas).
fuente
Las dos cosas que me ayudaron mejor al aprender allí fueron:
Capítulo 8, "Analizadores funcionales", del libro de Graham Hutton Programming in Haskell . En realidad, esto no menciona a las mónadas, pero si puede trabajar en el capítulo y comprender realmente todo lo que contiene, particularmente cómo se evalúa una secuencia de operaciones de enlace, comprenderá las partes internas de las mónadas. Espere que esto tome varios intentos.
El tutorial Todo sobre las mónadas . Esto da varios buenos ejemplos de su uso, y debo decir que la analogía en Appendex funcionó para mí.
fuente
Monoid parece ser algo que garantiza que todas las operaciones definidas en un Monoid y un tipo compatible siempre devolverán un tipo compatible dentro del Monoid. Por ejemplo, Cualquier número + Cualquier número = Un número, sin errores.
Mientras que la división acepta dos fraccionarios, y devuelve un fraccionario, que definió la división por cero como Infinito en haskell somewhy (que resulta ser fraccional somewhy) ...
En cualquier caso, parece que las mónadas son solo una forma de garantizar que su cadena de operaciones se comporte de una manera predecible, y una función que dice ser Num -> Num, compuesta con otra función de Num-> Num llamada con x no digamos, dispara los misiles.
Por otro lado, si tenemos una función que dispara los misiles, podemos componerla con otras funciones que también disparan los misiles, porque nuestra intención es clara: queremos disparar los misiles, pero no lo intentaremos imprimiendo "Hello World" por alguna extraña razón.
En Haskell, main es de tipo IO (), o IO [()], la discreción es extraña y no lo discutiré, pero esto es lo que creo que sucede:
Si tengo main, quiero que haga una cadena de acciones, la razón por la que ejecuto el programa es para producir un efecto, generalmente a través de IO. Por lo tanto, puedo encadenar las operaciones de IO en main para - hacer IO, nada más.
Si trato de hacer algo que no "devuelve IO", el programa se quejará de que la cadena no fluye, o básicamente "¿Cómo se relaciona esto con lo que estamos tratando de hacer? Una acción de IO", parece forzar el programador debe mantener su línea de pensamiento, sin desviarse y sin pensar en disparar los misiles, mientras crea algoritmos para la clasificación, que no fluye.
Básicamente, las mónadas parecen ser una sugerencia para el compilador que "oye, conoces esta función que devuelve un número aquí, en realidad no siempre funciona, a veces puede producir un número, y a veces nada en absoluto, solo mantén esto en mente". Sabiendo esto, si intentas afirmar una acción monádica, la acción monádica puede actuar como una excepción de tiempo de compilación diciendo "oye, esto no es realmente un número, PUEDE ser un número, pero no puedes asumir esto, haz algo para garantizar que el flujo sea aceptable ". lo que evita un comportamiento impredecible del programa, en buena medida.
Parece que las mónadas no tienen que ver con la pureza, ni con el control, sino con el mantenimiento de una identidad de una categoría en la que todo comportamiento es predecible y definido, o no se compila. No puede hacer nada cuando se espera que haga algo, y no puede hacer algo si se espera que no haga nada (visible).
La razón más importante por la que se me ocurre para Monads es: mira el código de procedimiento / OOP, y notarás que no sabes dónde comienza o termina el programa, todo lo que ves es un montón de saltos y muchas matemáticas , magia y misiles. No podrá mantenerlo, y si puede, pasará mucho tiempo concentrando su mente en todo el programa antes de que pueda comprender cualquier parte del mismo, porque la modularidad en este contexto se basa en "secciones" interdependientes de código, donde el código está optimizado para estar lo más relacionado posible para la promesa de eficiencia / interrelación. Las mónadas son muy concretas y están bien definidas por definición, y aseguran que el flujo del programa sea posible de analizar, y aislar partes que son difíciles de analizar, ya que ellas mismas son mónadas. Una mónada parece ser un " o destruir el universo o incluso distorsionar el tiempo: no tenemos ni idea ni garantías de que ES LO QUE ES. Una mónada GARANTIZA QUE ES LO QUE ES. que es muy poderoso o destruir el universo o incluso distorsionar el tiempo: no tenemos ni idea ni garantías de que ES LO QUE ES. Una mónada GARANTIZA QUE ES LO QUE ES. que es muy poderoso
Todas las cosas en el "mundo real" parecen ser mónadas, en el sentido de que está sujeto a leyes observables definidas que evitan la confusión. Esto no significa que tengamos que imitar todas las operaciones de este objeto para crear clases, sino que simplemente podemos decir "un cuadrado es un cuadrado", nada más que un cuadrado, ni siquiera un rectángulo ni un círculo, y "un cuadrado tiene área de la longitud de una de sus dimensiones existentes multiplicada por sí misma. No importa qué cuadrado tenga, si es un cuadrado en el espacio 2D, su área no puede ser más que su longitud al cuadrado, es casi trivial probarlo. Esto es muy poderoso porque no necesitamos hacer afirmaciones para asegurarnos de que nuestro mundo sea como es, solo usamos las implicaciones de la realidad para evitar que nuestros programas se salgan del camino.
Estoy casi seguro de estar equivocado, pero creo que esto podría ayudar a alguien, así que espero que ayude a alguien.
fuente
En el contexto de Scala, encontrará que la siguiente es la definición más simple. Básicamente flatMap (o enlace) es 'asociativo' y existe una identidad.
P.ej
NOTA Estrictamente hablando, la definición de una mónada en la programación funcional no es la misma que la definición de una mónada en la teoría de categorías , que se define en turnos de
map
yflatten
. Aunque son una especie de equivalente bajo ciertas asignaciones. Esta presentación es muy buena: http://www.slideshare.net/samthemonad/monad-presentation-scala-as-a-categoryfuente
Esta respuesta comienza con un ejemplo motivador, funciona a través del ejemplo, deriva un ejemplo de una mónada y define formalmente "mónada".
Considere estas tres funciones en pseudocódigo:
f
toma un par ordenado del formulario<x, messages>
y devuelve un par ordenado. Deja el primer elemento intacto y se agrega"called f. "
al segundo elemento. Lo mismo cong
.Puede componer estas funciones y obtener su valor original, junto con una cadena que muestra en qué orden se llamaron las funciones:
Que no le gusta el hecho de que
f
yg
es responsable de sus propios añadiendo mensajes de registro de la información de registro anterior. (Solo imagine por el argumento de que en lugar de agregar cadenas,f
yg
debe realizar una lógica complicada en el segundo elemento del par. Sería un dolor repetir esa lógica complicada en dos, o más, funciones diferentes).Prefieres escribir funciones más simples:
Pero mira lo que sucede cuando los compones:
El problema es que pasar un par a una función no te da lo que quieres. Pero, ¿y si pudieras alimentar un par en una función?
Leer
feed(f, m)
como "alimentarm
enf
". Para alimentar a una pareja<x, messages>
en una funciónf
es a pasarx
enf
, obtener<y, message>
fuera def
, y volver<y, messages message>
.Observe lo que sucede cuando hace tres cosas con sus funciones:
Primero: si ajusta un valor y luego alimenta el par resultante en una función:
Eso es lo mismo que pasar el valor a la función.
Segundo: si alimentas un par en
wrap
:Eso no cambia la pareja.
Tercero: si se define una función que toma
x
y se alimentag(x)
enf
:y alimentar un par en él:
Es lo mismo que alimentar al par
g
y alimentar al par resultantef
.Tienes la mayor parte de una mónada. Ahora solo necesita saber acerca de los tipos de datos en su programa.
¿Qué tipo de valor es
<x, "called f. ">
? Bueno, eso depende de qué tipo de valorx
sea. Six
es de tipot
, entonces su par es un valor de tipo "par det
y cadena". Llama a ese tipoM t
.M
es un constructor de tipos:M
solo no se refiere a un tipo, sino que seM _
refiere a un tipo una vez que completa el espacio en blanco con un tipo. UnM int
es un par de int y una cadena. UnM string
es un par de una cadena y una cadena. Etc.¡Felicitaciones, has creado una mónada!
Formalmente, tu mónada es la tupla
<M, feed, wrap>
.Una mónada es una tupla
<M, feed, wrap>
donde:M
es un constructor de tipos.feed
toma una (función que toma unat
y devuelve unaM u
) y unaM t
y devuelve unaM u
.wrap
toma unv
y devuelve unM v
.t
,u
yv
son tres tipos que pueden ser o no iguales. Una mónada satisface las tres propiedades que probó para su mónada específica:Alimentar una función envuelta
t
en una función es lo mismo que pasar la función no envueltat
a la función.Formalmente:
feed(f, wrap(x)) = f(x)
La alimentación de un
M t
awrap
no hace nada para elM t
.Formalmente:
feed(wrap, m) = m
Alimentando un
M t
(llámelom
) en una función quet
alg
M u
(llámalon
) deg
n
enf
es lo mismo que
m
ag
n
deg
n
af
Formalmente:
feed(h, m) = feed(f, feed(g, m))
dondeh(x) := feed(f, g(x))
Por lo general,
feed
se llamabind
(AKA>>=
en Haskell) ywrap
se llamareturn
.fuente
Trataré de explicar
Monad
en el contexto de Haskell.En la programación funcional, la composición de funciones es importante. Permite que nuestro programa consista en funciones pequeñas y fáciles de leer.
Digamos que tenemos dos funciones:
g :: Int -> String
yf :: String -> Bool
.Podemos hacer
(f . g) x
, que es lo mismo quef (g x)
, dondex
hay unInt
valor.Al hacer composición / aplicar el resultado de una función a otra, es importante que los tipos coincidan. En el caso anterior, el tipo del resultado devuelto por
g
debe ser el mismo que el tipo aceptado porf
.Pero a veces los valores están en contextos, y esto hace que sea un poco menos fácil alinear tipos. (Tener valores en contextos es muy útil. Por ejemplo, el
Maybe Int
tipo representa unInt
valor que puede no estar allí, elIO String
tipo representa unString
valor que está allí como resultado de realizar algunos efectos secundarios).Digamos que ahora tenemos
g1 :: Int -> Maybe String
yf1 :: String -> Maybe Bool
.g1
yf1
son muy similares ag
yf
respectivamente.No podemos hacer
(f1 . g1) x
of1 (g1 x)
, dondex
hay unInt
valor. El tipo de resultado devuelto porg1
no es el que sef1
espera.Podríamos componer
f
yg
con el.
operador, pero ahora no podemos componerf1
yg1
con.
. El problema es que no podemos pasar directamente un valor en un contexto a una función que espera un valor que no está en un contexto.¿No sería bueno si presentamos un operador para componer
g1
yf1
, de modo que podamos escribir(f1 OPERATOR g1) x
?g1
devuelve un valor en un contexto. El valor se sacará de contexto y se aplicará af1
. Y sí, tenemos un operador así. Es<=<
.También tenemos el
>>=
operador que hace por nosotros exactamente lo mismo, aunque en una sintaxis ligeramente diferente.Escribimos:
g1 x >>= f1
.g1 x
es unMaybe Int
valor El>>=
operador ayuda a sacar eseInt
valor del contexto de "quizás no existe" y aplicarlof1
. El resultado def1
, que es aMaybe Bool
, será el resultado de toda la>>=
operación.Y finalmente, ¿por qué es
Monad
útil? PorqueMonad
es la clase de tipo que define el>>=
operador, muy similar a laEq
clase de tipo que define los operadores==
y/=
.Para concluir, la
Monad
clase de tipo define el>>=
operador que nos permite pasar valores en un contexto (los denominamos valores monádicos) a funciones que no esperan valores en un contexto. El contexto será atendido.Si hay algo que recordar aquí, es que
Monad
permite la composición de funciones que involucra valores en contextos .fuente
tl; dr
Prólogo
El operador
$
de la aplicación de funcionesse define canónicamente
en términos de aplicación de función primitiva Haskell
f x
(infixl 10
).La composición
.
se define en términos de$
comoy satisface las equivalencias
forall f g h.
.
es asociativo, yid
es su identidad derecha e izquierda.El triple de Kleisli
En programación, una mónada es un constructor de tipo functor con una instancia de la clase de tipo mónada. Hay varias variantes equivalentes de definición e implementación, cada una con intuiciones ligeramente diferentes sobre la abstracción de la mónada.
Un functor es un constructor
f
de tipo de tipo* -> *
con una instancia de la clase de tipo functor.Además de seguir el protocolo de tipo forzado estáticamente, las instancias de la clase de tipo functor deben obedecer las leyes de funge algebraicas
forall f g.
Los cálculos de functor tienen el tipo
Un cálculo
c r
consiste en resultadosr
dentro del contextoc
.Las funciones monádicas unarias o las flechas de Kleisli tienen el tipo
Las flechas de Kleisi son funciones que toman un argumento
a
y devuelven un cálculo monádicom b
.Las mónadas se definen canónicamente en términos del triple de Kleisli
forall m. Functor m =>
implementado como la clase de tipo
La identidad de Kleisli
return
es una flecha de Kleisli que promueve un valort
en un contexto monádicom
. La aplicación de extensión o Kleisli=<<
aplica una flecha de Kleislia -> m b
a los resultados de un cálculom a
.La composición de Kleisli
<=<
se define en términos de extensión como<=<
compone dos flechas Kleisli, aplicando la flecha izquierda a los resultados de la aplicación de la flecha derecha.Las instancias de la clase de tipo mónada deben obedecer las leyes de mónada , más elegantemente expresadas en términos de composición de Kleisli:
forall f g h.
<=<
es asociativo, yreturn
es su identidad derecha e izquierda.Identidad
El tipo de identidad
es la función de identidad en tipos
Interpretado como un functor,
En Haskell canónico, se define la mónada de identidad
Opción
Un tipo de opción
codifica la computación
Maybe t
que no necesariamente produce un resultadot
, computación que puede "fallar". La opción mónada está definidaa -> Maybe b
se aplica a un resultado solo siMaybe a
produce un resultado.Los números naturales pueden codificarse como aquellos enteros mayores o iguales a cero.
Los números naturales no se cierran bajo resta.
La opción mónada cubre una forma básica de manejo de excepciones.
Lista
La mónada de la lista, sobre el tipo de lista
y su operación monoide aditiva "agregar"
codifica el cálculo no lineal que
[t]
produce una cantidad natural0, 1, ...
de resultadost
.La extensión
=<<
concatena++
todas las listas[b]
resultantes de las aplicacionesf x
de una flecha de Kleislia -> [b]
a elementos de[a]
una sola lista de resultados[b]
.Deje que los divisores propios de un entero positivo
n
seanentonces
Al definir la clase de tipo mónada, en lugar de extensión
=<<
, el estándar Haskell usa su operador flip, el enlace>>=
.Por simplicidad, esta explicación usa la jerarquía de clases de tipos
En Haskell, la jerarquía estándar actual es
porque no solo cada mónada es functor, sino que cada aplicativo es un ficticio y cada mónada también es un aplicativo.
Usando la lista mónada, el pseudocódigo imperativo
se traduce aproximadamente al bloque do ,
la comprensión de mónada equivalente ,
y la expresión
La comprensión de notación y mónada son azúcar sintáctica para expresiones de enlace anidadas. El operador de enlace se usa para el enlace de nombre local de resultados monádicos.
dónde
La función de guardia está definida
donde el tipo de unidad o "tupla vacía"
Las mónadas aditivas que admiten elección y falla pueden abstraerse utilizando una clase de tipo
donde
fail
y<|>
formar un monoideforall k l m.
y
fail
es el elemento cero absorbente / aniquilador de mónadas aditivasSi en
even p
es cierto, entonces el guardia produce[()]
y, por definición de>>
, la función constante localse aplica al resultado
()
. Si es falso, el guardia produce la lista mónadafail
([]
), que no produce ningún resultado para que se aplique una flecha de Kleisli>>
, por lo que estop
se omite.Estado
Infamemente, las mónadas se utilizan para codificar la computación con estado.
Un procesador de estado es una función.
que transiciona un estado
st
y produce un resultadot
. El estadost
puede ser cualquier cosa. Nada, bandera, conteo, matriz, mango, máquina, mundo.El tipo de procesadores de estado generalmente se llama
La mónada del procesador de estado es el
* -> *
functor amableState st
. Las flechas de Kleisli de la mónada del procesador de estado son funcionesEn Haskell canónico, se define la versión perezosa de la mónada del procesador de estado
Un procesador de estado se ejecuta proporcionando un estado inicial:
El acceso estatal es proporcionado por primitivas
get
yput
métodos de abstracción sobre mónadas con estado :m -> st
declara una dependencia funcional del tipo de estadost
en la mónadam
; que aState t
, por ejemplo, determinará que el tipo de estado seat
exclusivo.con el tipo de unidad utilizado de forma análoga a
void
en C.gets
A menudo se utiliza con los accesos de campo de registro.El estado de la mónada equivalente del subproceso variable
donde
s0 :: Int
, es el igualmente referencialmente transparente, pero infinitamente más elegante y prácticomodify (+ 1)
es un cálculo de tipoState Int ()
, excepto por su efecto equivalente areturn ()
.La ley de asociatividad de la mónada se puede escribir en términos de
>>=
forall m f g.
o
Al igual que en la programación orientada a la expresión (por ejemplo, Rust), la última declaración de un bloque representa su rendimiento. El operador de enlace a veces se denomina "punto y coma programable".
Las primitivas de la estructura de control de iteración de la programación imperativa estructurada se emulan monádicamente.
De entrada y salida
La mónada del procesador de estado mundial de E / S es una reconciliación de Haskell puro y el mundo real, de semántica operativa imperativa y denotativa funcional. Un análogo cercano de la implementación estricta real:
La interacción es facilitada por primitivas impuras
La impureza del código que usa
IO
primitivas está permanentemente protocolizada por el sistema de tipos. Debido a que la pureza es asombrosa, lo que sucede enIO
, se queda adentroIO
.O, al menos, debería.
La firma tipo de un programa Haskell
se expande a
Una función que transforma un mundo.
Epílogo
La categoría cuyos objetos son tipos de Haskell y qué morfismos son funciones entre los tipos de Haskell es, "rápido y suelto", la categoría
Hask
.Un functor
T
es un mapeo de una categoríaC
a una categoríaD
; para cada objeto enC
un objeto enD
y para cada morfismo en
C
un morfismo enD
donde
X
,Y
son objetos enC
.HomC(X, Y)
es la clase de homomorfismo de todos los morfismosX -> Y
enC
. El functor debe preservar la identidad y composición del morfismo, la "estructura" deC
, enD
.La categoría Kleisli de una categoría
C
está dada por un triple Kleislide un endofunctor
(
f
), un morfismo de identidadeta
(return
) y un operador de extensión*
(=<<
).Cada morfismo de Kleisli en
Hask
por el operador de extensión
se le da un morfismo en
Hask
la categoría de KleisliLa composición en la categoría Kleisli
.T
se da en términos de extensióny satisface los axiomas de categoría
que, aplicando las transformaciones de equivalencia
en términos de extensión se dan canónicamente
Las mónadas también se pueden definir en términos no de extensión de Kleislian, sino de una transformación natural
mu
, en la programación llamadajoin
. Una mónada se define en términos demu
un triple sobre una categoríaC
, de un endofunctory dos transformaciones naturales
satisfaciendo las equivalencias
La clase de tipo mónada se define entonces
La
mu
implementación canónica de la opción mónada:La
concat
funciónes el
join
de la lista mónada.Las implementaciones de
join
se pueden traducir del formulario de extensión utilizando la equivalenciaLa traducción inversa de
mu
a forma de extensión viene dada porPhilip Wadler: mónadas para la programación funcional
Simon L Peyton Jones, Philip Wadler: programación funcional imperativa
Jonathan MD Hill, Keith Clarke: una introducción a la teoría de categorías, las mónadas de teoría de categorías y su relación con la programación funcional ´
Categoría Kleisli
Eugenio Moggi: nociones de computación y mónadas
Lo que no es una mónada
de generalizar mónadas a flechas por John Hughes
fuente
Lo que el mundo necesita es otra publicación de blog de mónada, pero creo que esto es útil para identificar mónadas existentes en la naturaleza.
fuente
http://code.google.com/p/monad-tutorial/ es un trabajo en progreso para abordar exactamente esta pregunta.
fuente
Deje que el "
{| a |m}
" siguiente represente algún dato monádico. Un tipo de datos que anuncia una
:La función,
f
sabe cómo crear una mónada, si solo tuviera una
:Aquí vemos la función,
f
intenta evaluar una mónada pero es reprendido.Funtion,
f
encuentra una forma de extraer ela
mediante>>=
.Poco
f
sabe, la mónada y>>=
están en colusión.¿Pero de qué hablan realmente? Bueno, eso depende de la mónada. Hablar únicamente en abstracto tiene un uso limitado; tienes que tener alguna experiencia con mónadas particulares para desarrollar el entendimiento.
Por ejemplo, el tipo de datos Quizás
tiene una instancia de mónada que actuará de la siguiente manera ...
En donde, si el caso es
Just a
Pero para el caso de
Nothing
Entonces, la mónada tal vez permite que un cálculo continúe si realmente contiene lo
a
que anuncia, pero aborta el cálculo si no lo hace. El resultado, sin embargo, sigue siendo un dato monádico, aunque no el resultado def
. Por esta razón, la mónada Quizás se usa para representar el contexto del fracaso.Las diferentes mónadas se comportan de manera diferente. Las listas son otros tipos de datos con instancias monádicas. Se comportan de la siguiente manera:
En este caso, la función sabía cómo hacer una lista a partir de su entrada, pero no sabía qué hacer con entradas adicionales y listas adicionales. El enlace
>>=
, ayudadof
mediante la combinación de las múltiples salidas. Incluyo este ejemplo para mostrar que si bien>>=
es responsable de la extraccióna
, también tiene acceso a la salida eventual def
. De hecho, nunca extraerá ninguno aa
menos que sepa que el resultado final tiene el mismo tipo de contexto.Hay otras mónadas que se utilizan para representar diferentes contextos. Aquí hay algunas caracterizaciones de algunas más. La
IO
mónada en realidad no tiene una
, pero conoce a un chico y lo conseguiráa
por ti. LaState st
mónada tiene un alijo secreto dest
que pasaráf
debajo de la mesa, a pesar de quef
acaba de llegar pidiendo una
. LaReader r
mónada es similar aState st
, a pesar de que sólo dejaf
verr
.El punto en todo esto es que cualquier tipo de datos que se declare a sí mismo como una mónada está declarando algún tipo de contexto en torno a la extracción de un valor de la mónada. ¿La gran ganancia de todo esto? Bueno, es bastante fácil armar un cálculo con algún tipo de contexto. Sin embargo, puede volverse desordenado al unir varios cálculos cargados de contexto. Las operaciones de mónada se encargan de resolver las interacciones de contexto para que el programador no tenga que hacerlo.
Tenga en cuenta que el uso de la
>>=
facilita un desastre al quitarle algo de autonomíaf
. Es decir, en el caso anterior,Nothing
por ejemplo,f
ya no se puede decidir qué hacer en el caso deNothing
; se codifica en>>=
. Esta es la compensación. Si fue necesariof
decidir qué hacer en el caso deNothing
, entoncesf
debería haber sido una función desdeMaybe a
hastaMaybe b
. En este caso,Maybe
ser una mónada es irrelevante.Tenga en cuenta, sin embargo, que a veces un tipo de datos no exporta sus constructores (mirándolo IO), y si queremos trabajar con el valor anunciado, tenemos pocas opciones más que trabajar con su interfaz monádica.
fuente
Una mónada es una cosa utilizada para encapsular objetos que tienen un estado cambiante. Se encuentra con mayor frecuencia en idiomas que, de lo contrario, no le permiten tener un estado modificable (por ejemplo, Haskell).
Un ejemplo sería para el archivo de E / S.
Podrías usar una mónada para E / S de archivo para aislar la naturaleza de estado cambiante solo para el código que usó la mónada. El código dentro de la mónada puede ignorar efectivamente el estado cambiante del mundo fuera de la mónada; esto hace que sea mucho más fácil razonar sobre el efecto general de su programa.
fuente