¿Qué problemas de programación resuelven las mónadas? [cerrado]

14

He leído muchas publicaciones que explican qué son las mónadas, cómo unity cómo bindfuncionan, algunas de ellas sumergiéndose directamente en la teoría de categorías tan abstracta (al menos para mí) que hace que los ojos sangren, algunas ignorando eso por completo y tocando analogías extrañas de burritos, cajas y que no.

Después de algunas semanas de estudio y muchas neuronas fritas, (creo) entiendo cómo funcionan las mónadas. Pero todavía hay una cosa que se me escapa, algo que pocas publicaciones realmente tocan (a excepción de IO y estado):

¿POR QUÉ?

¿Por qué importan las mónadas? ¿Por qué son tan importantes? ¿Qué problemas están resolviendo? ¿Esos problemas solo se pueden resolver con Mónadas o hay alguna otra forma?

Dummy Me
fuente
3
Los programas son grandes y complejos. Necesitamos formas de estructurarlos. Hay muchas maneras. Las mónadas son una. Las flechas son una. Los functores son uno. Objetos, clases, funciones, métodos, módulos, rasgos, mixins, paquetes, son algunos otros. Realmente no está claro cuál es su pregunta específica. ¿Se pregunta por qué necesitamos estructurar programas?
Jörg W Mittag
1
@ JörgWMittag: NO pregunto por qué necesitamos estructurar programas. Obviamente, un gran problema se divide en otros más pequeños que puede resolver y luego combinar para obtener la solución para el gran problema. Me pregunto qué problemas resuelven las mónadas. ¿Es asi? Código de estructuración? ¿De eso se trata todo el alboroto? Por ejemplo, en Haskell así es como se hacen las E / S. Allí, la mónada es una obra de teatro que actúa como algo puro cuando en realidad no lo es. Mi pregunta está en el título, no sé cómo decirlo de una manera más clara.
Dummy Me
2
¿Por qué mónadas?
Robert Harvey
1
@RobertHarvey: También encontré los primeros dos enlaces que agregaste, pero al igual que en las respuestas de esas y otras publicaciones, las respuestas van directamente a Talad, State e IO mónadas, saltando rápidamente a ejemplos o código, y terminan con "hay mucho de problemas que se pueden resolver con Mónadas ". ¿Cuáles son los otros tipos de problemas? Estoy buscando una respuesta de nivel superior que, en lugar de reiterar los mismos ejemplos, vaya a la raíz de los problemas (cualesquiera que sean) y explique cómo las Mónadas los resuelven y por qué es la mejor opción, en lugar de usar otra cosa. Sin embargo, muchas gracias por los comentarios.
Dummy Me

Respuestas:

10

No necesitas mónadas para resolver nada. Simplemente hacen que ciertas cosas sean más simples. Mucha gente se vuelve demasiado abstracta y teórica al explicar las mónadas. En su mayoría, las mónadas son un patrón que aparece una y otra vez en la programación. Al reconocer ese patrón, podemos simplificar nuestro código y evitar volver a implementar ciertas funciones.

Para Haskell, desde un punto de vista concreto, lo más visible que permiten las mónadas es hacer notación . Las comprensiones de listas en Haskell y otros idiomas también aprovechan mucho las mónadas. También puede crear bibliotecas como Control.Monad .

Todos estos proporcionan simplificaciones útiles, y una vez que lo ha implementado para una mónada, lo obtiene automáticamente para todas las mónadas. Esta es una de las principales razones por las que la reutilización de código es mucho más fácil para la programación funcional que otros paradigmas.

Karl Bielefeldt
fuente
2
De hecho, diría que lo más visible que permiten las mónadas de Haskell es una manera fácil de tener efectos de E / S que realmente funcionan de la manera esperada. Creo que cualquiera que se pregunte qué nos dan las mónadas debería probar Miranda . Miranda es el idioma que Haskell fue diseñado para reemplazar, y debería ser muy fácil de aprender para cualquier persona con experiencia en Haskell. La principal diferencia es que no tiene IO monádica, lo que hace que el lenguaje sea mucho más difícil de trabajar que Haskell para cualquier proyecto no trivial.
Jules
Sí, IOes la mónada más prominente de Haskell , pero no estaba enumerando ejemplos de mónadas individuales. Estaba enumerando ejemplos de las abstracciones generales que permiten. Estaba tratando de entender por qué, por ejemplo, el primer tipo en pensar en usar una mónada para IO pensaría que es una buena idea en general.
Karl Bielefeldt
1
@Jules: O mira la historia de Haskell. Antes de Monads, los diseñadores de Haskell experimentaron con Lazy Streams y Continuations como la base de E / S, y ambos fueron difíciles de usar.
Jörg W Mittag
5

Es más fácil de entender si observa las mónadas particulares y ve qué problemas resuelven. Por ejemplo, en Haskell:

  • IO: permite que IO se represente en el sistema de tipos, por lo que puede separar claramente las funciones puras de las funciones que realizan IO.

  • Lista: le permite hacer comprensiones de listas y cálculos terminológicos de nodo.

  • Quizás: una mejor alternativa a los valores nulos y que respalde algo comparable al operador de fusión nula de C #.

  • Parsec: un conveniente DSL para escribir analizadores.

Por lo tanto, es fácil (espero) ver la justificación de las mónadas individuales, ya que todas son bastante útiles. Pero los problemas que resuelven también son bastante diferentes y, a primera vista, no parecen tener mucho en común, excepto que todos están relacionados con alguna lógica para encadenar operaciones. Las mónadas son útiles porque le permiten construir una variedad de herramientas.

¿Podrían implementarse los ejemplos anteriores sin mónadas? Ciertamente, podrían implementarse de manera ad-hoc, pero tener mónadas integradas en el lenguaje permite el soporte directo del lenguaje como la donotación que funciona con todas las mónadas.

JacquesB
fuente
2

Una cosa que lo hace confuso es que las funciones "populares" les gusta bindy <*>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 fque 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 fmapo 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 Functory 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.

Monades 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 Monads join, nos permite combinar dos contextos apilados del mismo tipo. Lo mismo ocurre con los analizadores sintácticos, Quizás, etc. Y bindes 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.

Marlin
fuente
1

Monads le permite expresar varios cálculos no puros, así como simplificar el código

  • cálculo con estado (obtener / establecer estado a través de mónada)
  • E / S (registro, UI, archivo o simplemente producir / consumir una lista de X)
  • Además, el flujo de control "no lineal" (es decir, excepciones, tal vez, etc.)

Y, lo que es más importante, sin comprometer las construcciones de lenguaje puro y obtener un lenguaje más limpio.

Macke
fuente
2
Cierto, pero eso es solo una parte de para qué se usan las mónadas. Lista de comprensiones o Maybeno están relacionadas con nada externo.
JacquesB
Sería útil si los votantes negativos explican por qué lo han hecho. No veo nada malo con esta respuesta.
Jules
@JacquesB son, sin embargo, con estado.
Jules
1
Sin embargo, los tipos de mundo, los tipos de singularidad y los tipos lineales también le permiten hacer eso.
Jörg W Mittag
@Jules Listas como una mónada no determinista es con estado? ¿Podría aclarar cuál es su definición de "con estado"?
Jack