Pregunta ¿Qué es una mónada?


Después de haber mirado brevemente a Haskell recientemente, ¿qué sería una breve, sucinto, práctico explicación sobre qué es una mónada en esencia?

He encontrado que la mayoría de las explicaciones que he encontrado son bastante inaccesibles y carecen de detalles prácticos.


1227


origen


Respuestas:


Primero: el término monada es un poco vacío si no eres un matemático. Un término alternativo es constructor de cómputo que es un poco más descriptivo de para qué son realmente útiles.

Usted pide ejemplos prácticos:

Ejemplo 1: comprensión de la lista:

[x*2 | x<-[1..10], odd x]

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 realmente solo azúcar sintáctica para algunas operaciones dentro de la lista de mónadas. La misma lista de comprensión se puede escribir como:

do
   x <- [1..10]
   if odd x 
       then [x * 2] 
       else []

O incluso:

[1..10] >>= (\x -> if odd x then [x*2] else [])

Ejemplo 2: Entrada / Salida:

do
   putStrLn "What is your name?"
   name <- getLine
   putStrLn ("Welcome, " ++ name ++ "!")

Ambos ejemplos usan mónadas, constructores de computación AKA. El tema común es que la mónada operaciones de cadenas de alguna manera específica, útil. En la lista de comprensión, las operaciones están encadenadas de modo que si una operación devuelve una lista, se realizan las siguientes operaciones en cada artículo en la lista. La mónima IO, por otro lado, realiza las operaciones secuencialmente, pero pasa una "variable oculta" a lo largo, que representa "el estado del mundo", lo 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: el uso del Error mónada, las operaciones están encadenadas de forma tal que se realizan de forma secuencial, excepto si se produce un error, en cuyo caso el resto de la cadena se abandona.

Tanto la sintaxis de comprensión de lista como la notación de do son azúcar sintáctica para operaciones de encadenamiento que utilizan >>= operador. Una mónada es básicamente un tipo que admite el >>= operador.

Ejemplo 3: un analizador

Este es un analizador muy simple que analiza una cadena entre comillas o un número:

parseExpr = parseString <|> parseNumber

parseString = do
        char '"'
        x <- many (noneOf "\"")
        char '"'
        return (StringValue x)

parseNumber = do
    num <- many1 digit
    return (NumberValue (read num))

Las operaciones char, digit, etc. son bastante simples. Ellos coinciden o no coinciden. La magia es la mónada que gestiona el flujo de control: las operaciones se realizan secuencialmente hasta que falla una coincidencia, en cuyo caso la mónada retrocede a la última <|> e intenta la siguiente opción. De nuevo, una forma de encadenar operaciones con alguna semántica adicional y útil.

Ejemplo 4: Programación asincrónica

Los ejemplos anteriores están en Haskell, pero resulta F# también es compatible con mónadas. Este ejemplo es robado Don Syme:

let AsyncHttp(url:string) =
    async {  let req = WebRequest.Create(url)
             let! rsp = req.GetResponseAsync()
             use stream = rsp.GetResponseStream()
             use reader = new System.IO.StreamReader(stream)
             return reader.ReadToEnd() }

Este método busca una página web. La línea de golpe es el uso de GetResponseAsync - realmente espera la respuesta en un hilo separado, mientras que el hilo principal vuelve de la función. Las últimas tres líneas se ejecutan en el subproceso generado cuando se recibe la respuesta.

En la mayoría de los demás idiomas, debería crear explícitamente una función separada para las líneas que manejan la respuesta. los async mónada es capaz de "dividir" el bloque por sí mismo y posponer la ejecución de la segunda mitad. (Los async {} la sintaxis indica que el flujo de control en el bloque está definido por async monada.)

Cómo trabajan ellos

Entonces, ¿cómo puede una mónada hacer todas estas cosas elegantes de control de flujo? Lo que realmente sucede en un do-block (o un expresión de cálculo como se llaman 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 (deletreado >>= en Haskell). Desde el bind la operación combina funciones, puede ejecutarlas como lo considere oportuno: secuencialmente, varias veces, al revés, descartar algunas, ejecutar algunas en una secuencia separada cuando se lo parezca y así sucesivamente.

Como ejemplo, esta es la versión expandida del código IO del ejemplo 2:

putStrLn "What is your name?"
>>= (\_ -> getLine)
>>= (\name -> putStrLn ("Welcome, " ++ name ++ "!"))

Esto es más feo, pero también es más obvio lo que está sucediendo realmente. los >>= 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 luego tomado por el siguiente >>= operador y de nuevo combinado con una función para producir un nuevo valor. >>= puede verse 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 >>=. (Todas las operaciones en la cadena tienen que 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 de la izquierda y lo aplica a la función de 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 >>=.

Existe cierta habilidad adicional en la forma en que los valores pasan de una operación a la siguiente, pero esto requiere una explicación más profunda del sistema de tipo Haskell.

Resumiendo

En Haskell-terms, una mónada es un tipo parametrizado que es una instancia de la clase de tipo Monad, que define >>= junto con algunos otros operadores. En términos simples, una mónada es solo un tipo para el cual >>= operación está definida.

En si mismo >>= es solo una forma engorrosa de encadenar funciones, pero con la presencia de notación do que oculta la "fontanería", las operaciones monádicas resultan ser una abstracción útil y útil, útiles en muchos lugares del lenguaje y útiles para crear sus mini-idiomas en el idioma.

¿Por qué las mónadas son duras?

Para muchos estudiantes 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 está basado en mónadas, y las E / S son probablemente una de las primeras cosas que quieres entender cuando aprendes un nuevo idioma. Después de todo, no es muy divertido crear programas que no producen ningún salida. No tengo una solución inmediata para este problema de huevo y gallina, excepto tratar 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


965



Explicar "qué es una mónada" es 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 infierno ¿Podrías explicar qué números son? ¿Y cómo comenzarías a describir por qué podría ser útil?

¿Qué es una mónada? La respuesta corta: es una forma específica de encadenar operaciones juntas.

Básicamente, está escribiendo pasos de ejecución y vinculándolos con la "función de enlace". (En Haskell, se llama >>=.) Puede escribir las llamadas al operador de enlace usted mismo, o puede usar el azúcar de sintaxis que hace que el compilador inserte esas llamadas de función para 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 enlace es tomar el resultado del paso anterior y alimentarlo en el próximo paso.

Eso no suena demasiado duro, ¿verdad? Pero hay más de uno tipo de mónada ¿Por qué? ¿Cómo?

Bueno, la función de enlace poder simplemente tome el resultado de un paso y alimente al siguiente paso. Pero si eso es "todo", la mónada lo hace ... eso en realidad no es muy útil. Y eso es importante de entender: cada útil la mónada hace algo más en adición simplemente ser una mónada. Cada útil la mónada tiene un "poder especial", lo que la hace única.

(Una mónada que hace nada especial se llama la "mónada de identidad". Más bien como la función de identidad, esto suena como una cosa completamente sin sentido, pero resulta que no es ... Pero esa es otra historia ™.)

Básicamente, cada mónada tiene su propia implementación de la función bind. Y puede escribir una función de vinculación de forma que no moleste entre los pasos de ejecución. Por ejemplo:

  • Si cada paso devuelve un indicador de éxito / falla, puede hacer que bind ejecute el siguiente paso solo si el anterior tuvo éxito. De esta forma, un paso fallido cancela la secuencia completa "automáticamente", sin que usted realice ninguna prueba condicional. (Los Failure Monad.)

  • Extendiendo esta idea, puede implementar "excepciones". (Los Error Monad o Excepción Monad.) Como los está definiendo usted mismo en lugar de ser una función de idioma, puede definir cómo funcionan. (Por ejemplo, tal vez quiera ignorar las dos primeras excepciones y abortar solo cuando tercero se lanza una excepción)

  • Puede hacer que cada paso regrese resultados múltiplesy haz que la función de vinculación se repita sobre ellos, alimentando a cada uno en el siguiente paso para ti. De esta forma, no tiene que seguir escribiendo bucles por todos lados cuando se trata de resultados múltiples. La función de enlace "automáticamente" hace todo eso por usted. (Los Lista Monad.)

  • Además de pasar un "resultado" de un paso a otro, puede tener la función de enlace pasar datos extra alrededor también. Esta información ahora no aparece en su código fuente, pero aún puede acceder a ella desde cualquier lugar, sin tener que pasarla manualmente a cada función. (Los Lector Monad.)

  • Puede hacerlo para que los "datos adicionales" puedan ser reemplazados. Esto te permite simular actualizaciones destructivas, sin hacer realmente actualizaciones destructivas. (Los Monad del estado y su primo el Escritor Monad.)

  • Porque solo eres simulando actualizaciones destructivas, puedes hacer trivialmente cosas que serían imposibles con real actualizaciones destructivas. Por ejemplo, puedes deshacer la última actualización, o volver a una versión anterior.

  • Puedes hacer una mónada donde los cálculos pueden ser pausado, por lo que puede pausar su programa, entrar y retocar los datos del estado interno, 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 mónadas. Por supuesto, todo esto también es perfectamente posible sin Mónadas también. Es solo drásticamente más fácil usando mónadas


638



En realidad, contrariamente 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 sobre las cosas envueltas sin desenvolverlas.

Por ejemplo, puede crear un tipo para ajustar otro, en Haskell:

data Wrapped a = Wrap a

Para envolver cosas definimos

return :: a -> Wrapped a
return x = Wrap x

Para realizar operaciones sin desenvolver, digamos que tiene una función f :: a -> b, entonces puedes hacer esto para ascensor esa función para actuar en valores envueltos:

fmap :: (a -> b) -> (Wrapped a -> Wrapped b)
fmap f (Wrap x) = Wrap (f x)

Eso es todo lo que hay para entender. Sin embargo, resulta que hay una función más general para hacer esto levantamiento, cual es bind:

bind :: (a -> Wrapped b) -> (Wrapped a -> Wrapped b)
bind f (Wrap x) = f x

bind puede hacer un poco más de fmap, pero no al revés Actualmente, fmap se puede definir solo en términos de bind y return. Entonces, al definir una mónada ... le das su tipo (aquí estaba Wrapped a) y luego decir cómo es return y bind las operaciones funcionan

Lo bueno es que esto resulta ser un patrón tan general que aparece por todos lados, encapsular el estado de una manera pura es solo uno de ellos.

Para obtener un buen artículo sobre cómo las mónadas se pueden utilizar para introducir dependencias funcionales y, por lo tanto, controlar el orden de evaluación, como se usa en la mónada IO de Haskell, echa un vistazo. 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 comprende de inmediato. Entonces solo 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 cuela en tu cerebro mediante la práctica; un día, de repente te das cuenta de que las entiendes.


164



Pero, ¡Podrías haber inventado Mónadas!

Sigfpe dice:

Pero todos estos introducen las mónadas como algo esotérico que necesita explicación. Pero lo que quiero decir es que no son esotéricos en absoluto. De hecho, frente a varios problemas en la programación funcional, usted habría sido conducido, inexorablemente, a ciertas soluciones, todas las cuales son ejemplos de mónadas. De hecho, espero conseguirte que los inventes ahora si aún no lo hiciste. Es entonces un pequeño paso darse cuenta de que todas estas soluciones son, de hecho, la misma solución disfrazada. Y después de leer esto, es posible que esté en una mejor posición para comprender otros documentos sobre mónadas porque reconocerá todo lo que ve como algo que ya ha inventado.

Muchos de los problemas que las mónadas intentan resolver están relacionados con el tema de los efectos secundarios. Entonces comenzaremos con ellos. (Tenga en cuenta que las mónadas le permiten hacer algo más que manejar los efectos secundarios, en particular, muchos tipos de objetos contenedores pueden verse como mónadas. Algunas de las introducciones a las mónadas encuentran difícil conciliar estos dos usos diferentes de las mónadas y concentrarse en solo uno o el otro.)

En un lenguaje de programación imperativo como C ++, las funciones no se comportan como las funciones de las matemáticas. Por ejemplo, supongamos que tenemos una función de C ++ que toma un único argumento de coma flotante y devuelve un resultado de punto flotante. Superficialmente, puede parecer un poco como una función matemática mapeando reales a reales, pero una función de C ++ puede hacer más que simplemente devolver un número que depende de sus argumentos. Puede leer y escribir los valores de variables globales, así como escribir resultados en la pantalla y recibir información del usuario. En un lenguaje funcional puro, sin embargo, una función solo puede leer lo que se le proporciona en sus argumentos y la única forma en que puede tener un efecto en el mundo es a través de los valores que devuelve.


161



Una mónada es un tipo de datos que tiene dos operaciones: >>= (aka bind) y return (aka unit) return toma un valor arbitrario y crea una instancia de la mónada con él. >>= toma una instancia de la mónada y mapea una función sobre ella. (Ya puede ver que una mónada es un tipo extraño de tipo de datos, 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 se cree un tipo a partir de ella. Las mónadas usan un tipo de polimorfismo paramétrico.)

En la notación Haskell, la interfaz de la mónada está escrita

class Monad m where
  return :: a -> m a
  (>>=) :: forall a b . m a -> (a -> m b) -> m b

Se supone que estas operaciones obedecen a ciertas "leyes", pero eso no es terriblemente importante: las "leyes" solo codifican la forma en que las implementaciones sensatas de las operaciones deben comportarse (básicamente, que >>= y return debería estar de acuerdo sobre cómo los valores se transforman en instancias de mónadas y que >>= es asociativo).

Las mónadas no son solo acerca del estado y la E / S: resumen un patrón común de computación que incluye trabajar con estado, E / S, excepciones y no determinismo. Probablemente las mónadas más simples de entender sean listas y tipos de opciones:

instance Monad [ ] where
    []     >>= k = []
    (x:xs) >>= k = k x ++ (xs >>= k)
    return x     = [x]

instance Monad Maybe where
    Just x  >>= k = k x
    Nothing >>= k = Nothing
    return x      = Just x

dónde [] y : son los constructores de lista, ++es el operador de concatenación, y Just y Nothing son el Maybe constructores Ambas mónadas encapsulan patrones comunes y útiles de computación en sus respectivos tipos de datos (tenga en cuenta que ninguno de los dos tiene nada que ver con efectos secundarios o E / S).

Realmente tienes que jugar a escribir un código Haskell no trivial para apreciar de qué mónadas se trata y por qué son útiles.


77



Primero debes entender qué es un functor. Antes de eso, entiende las funciones de orden superior.

UN función de orden superior es simplemente una función que toma una función como argumento.

UN functor es cualquier tipo de construcción T para lo cual existe una función de orden superior, llámala map, que transforma una función de tipo a -> b (dado dos tipos a y b) en una función T a -> T b. Esta map la función también debe obedecer las leyes de identidad y composición de tal manera que las siguientes expresiones devuelvan verdadero para todos p y q (Notación Haskell):

map id = id
map (p . q) = map p . map q

Por ejemplo, un constructor de tipo llamado List es un funtor si viene equipado con una función de tipo (a -> b) -> List a -> List b que obedece a las leyes anteriores. La única implementación práctica es obvia. La resultante List a -> List b función itera sobre la lista dada, llamando al (a -> b) función para cada elemento, y devuelve la lista de resultados.

UN monada es esencialmente solo un functor T con dos métodos adicionales, join, de tipo T (T a) -> T ay unit (aveces llamado return, fork, o pure) de tipo a -> T a. Para listas en Haskell:

join :: [[a]] -> [a]
pure :: a -> [a]

¿Por qué es eso útil? Porque podrías, 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 no map, entonces join. Esta función se llama bind, o flatMap, o (>>=), o (=<<). Esta es normalmente la forma en que se da una instancia de mónada en Haskell.

Una mónada tiene que cumplir ciertas leyes, a saber, que join debe ser asociativo Esto significa que si tienes un valor x de tipo [[[a]]] entonces join (join x) debería ser igual join (map join x). Y pure debe ser una identidad para join tal que join (pure x) == x.


70



[Descargo de responsabilidad: todavía estoy tratando de asimilar completamente las mónadas. Lo siguiente es exactamente lo que he entendido hasta ahora. Si está mal, con suerte alguien con conocimiento me llamará por la alfombra.]

Arnar escribió:

Las mónadas son simplemente una forma de envolver cosas y proporcionar métodos para realizar operaciones sobre las cosas envueltas sin desenvolverlas.

Eso es precisamente eso. La idea es así:

  1. 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 un IO.

  2. Luego tiene algunos operadores que le permiten operar con los datos envueltos mientras lleva 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, un Maybe Int puede ser un Just Int o Nothing. Ahora, si agrega un Maybe Int a un Maybe Int, el operador verificará si son ambos Just Ints dentro, y si es así, abrirá el Ints, páselos al operador de suma, vuelva a envolver el resultado Int en un nuevo Just Int (que es un valido Maybe Int), y así devolver un Maybe Int. Pero si uno de ellos era un Nothing adentro, este operador simplemente regresará inmediatamente Nothing, que nuevamente es un valido Maybe Int. De esa manera, puedes fingir que tu Maybe Ints son solo números normales y realizan cálculos regulares sobre ellos. Si fueras a obtener un Nothing, tus ecuaciones seguirán produciendo el resultado correcto - sin tener que tirar basura por los cheques Nothing en todos lados.

Pero el ejemplo es solo lo que sucede para Maybe. Si la información adicional era una IO, entonces ese operador especial definido para IOs se llamaría en su lugar, y podría hacer algo totalmente diferente antes de realizar la adición. (OK, agregando dos IO Ints juntos es probablemente absurdo, todavía no estoy seguro.) (También, si prestas atención al Maybe ejemplo, has 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" aproximadamente significa "patrón". Pero en lugar de un libro lleno de patrones informalmente explicados y específicamente nombrados, ahora tiene una construcción de lenguaje - sintaxis y todo eso - eso te permite declara nuevos patrones como cosas en tu 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 las mónadas tan confusas: porque son un concepto tan genérico. Preguntar qué hace que algo sea una mónada es igualmente vago que preguntar qué hace que algo sea un patrón.

Pero piense en las implicaciones de tener soporte sintáctico en el lenguaje para la idea de un patrón: en lugar de tener que leer el Pandilla de cuatro reservar y memorizar la construcción de un patrón particular, solo escriba el código que implementa este patrón de una manera agnóstica y genérica una vez y luego has terminado! A continuación, puede reutilizar este patrón, como Visitor, Strategy o Faade o lo que sea, simplemente decorando las operaciones en su código con él, ¡sin tener que volver a implementarlo una y otra vez!

Entonces esa es la razón por la cual la gente entender las mónadas los encuentran tan útil: no es un concepto de torre de marfil que los esnobs intelectuales se enorgullecen de la comprensión (OK, eso también, por supuesto, teehee), pero en realidad hace que el código sea más simple.


42



Después de mucho esfuerzo, creo que finalmente entiendo la mónada. Después de releer mi propia y larga crítica de la abrumadora respuesta más votado, ofreceré esta explicación.

Hay tres preguntas que deben ser respondidas para comprender las mónadas:

  1. ¿Por qué necesitas una mónada?
  2. ¿Qué es una mónada?
  3. ¿Cómo se implementa una mónada?

Como noté en mis comentarios originales, demasiadas explicaciones de mónadas quedan atrapadas en la pregunta número 3, sin, y antes de 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 eso, un programa funcional puro no necesariamente se ejecuta 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 cual puedes resolver la "ecuación" en cualquier cantidad 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 el archivo de E / S, necesitan que las cosas sucedan en un orden particular o que necesiten mantener el estado. Una forma de resolver 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 devuelvan un nuevo objeto de estado modificado.

Así que 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 bytes que representa lo que está actualmente visible 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, lo modifican y devuelven un nuevo estado de consola.

consolestate MyConsole = new consolestate;

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 uno.

consolestate FinalConsole = print(input(print(myconsole, "Hello, what's your name?")),"hello, %inputbuffer%!");

La programación de esta manera mantiene el estilo funcional "puro", al tiempo que obliga a realizar 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 anidación de esa manera comenzarán a ser desgarbadas. Lo que queremos es un código que esencialmente hace lo mismo que arriba, pero se escribe un poco más como este:

consolestate FinalConsole = myconsole:
                            print("Hello, what's your name?"):
                            input():
                            print("hello, %inputbuffer%!");

De hecho, esta sería una forma más conveniente de escribirlo. ¿Cómo hacemos eso?

¿Qué es una mónada?

Una vez que tiene un tipo (como consolestate) que define 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 : (enlace) que automáticamente proporciona valores de retorno a su izquierda, en parámetros de funciones a su derecha, y un lift 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?

Ver otras respuestas, que parecen bastante libres para saltar a los detalles de eso.


37



(Ver también las respuestas en ¿Qué es una mónada?)

Una buena motivación para Monads es sigfpe (Dan Piponi) 's ¡Podrías haber inventado mónadas! (Y tal vez ya lo haya hecho). Existen MUCHOS otros tutoriales de mónadas, muchos de los cuales intentan explicar incorrectamente las mónadas en "términos simples" usando varias analogías: este es el falsedad tutorial mónada; Evítales.

Como dice DR MacIver en Cuéntanos por qué tu lenguaje apesta:

Entonces, las cosas que odio de Haskell:

    Comencemos con lo obvio. Monad tutoriales. No, no mónadas. Específicamente los tutoriales. Son infinitos, exagerados y queridos Dios, son tediosos. Además, nunca he visto ninguna evidencia convincente de que realmente ayuden. Lee la definición de la clase, escribe un código, supera el nombre aterrador.

¿Dices que entiendes la Mónada Maybe? Bien, estás en camino. Simplemente comience a usar otras mónadas y tarde o temprano comprenderá qué mónadas son en general.

[Si está matemáticamente orientado, 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 Monad M implica un "constructor de tipo" que define para cada tipo existente "T" un nuevo tipo "MT", y algunas formas de ir y venir entre tipos "regulares" y "M" tipos]

Además, sorprendentemente, una de las mejores introducciones a las mónadas es en realidad uno de los primeros trabajos académicos que introdujeron mónadas, la de Philip Wadler. Mónadas para programación funcional. En realidad tiene practico, no trivial ejemplos motivadores, a diferencia de muchos de los tutoriales artificiales que existen.


33