functional-programming io monads side-effects

functional programming - ¿Cuál es la alternativa de las mónadas para usar IO en la programación funcional pura?



functional-programming monads (6)

¿Qué alternativas hay para mónadas para E / S en un lenguaje funcional puro?

Soy consciente de dos alternativas en la literatura:

  • Uno es un llamado sistema de tipo lineal . La idea es que un valor de tipo lineal debe usarse exactamente una vez: no puede ignorarlo, y no puede usarlo dos veces. Con esta idea en mente, le das al estado del mundo un tipo abstracto (por ejemplo, World ), y lo haces lineal. Si marcó tipos lineales con una estrella, estos son los tipos de algunas operaciones de E / S:

    getChar :: World* -> (Char, World*) putChar :: Char -> World* -> World*

    y así. El compilador se asegura de que nunca copies el mundo, y luego puede organizar la compilación del código que actualiza el mundo en su lugar, lo cual es seguro porque solo hay una copia.

    La singularidad de tipeo en el lenguaje Clean se basa en la linealidad.

    Este sistema tiene un par de ventajas; en particular, no impone el orden total en los eventos que hacen las mónadas. También tiende a evitar el " IO sin bin" que ves en Haskell, donde todos los cálculos efectivos se envían a la mónada de IO y todos se ordenan totalmente, independientemente de si deseas el orden total o no.

  • El otro sistema que conozco es anterior a las mónadas y Limpio, y se basa en la idea de que un programa interactivo es una función de una secuencia (posiblemente infinita) de solicitudes a una secuencia de respuestas (posiblemente infinita). Este sistema, que se llamaba "diálogos", era un infierno para programar. Nadie lo extraña, y no tenía nada en particular para recomendarlo. Sus fallas se enumeran muy bien en el documento que introdujo la E / S monádica ( Imperative Functional Programming ) de Wadler y Peyton Jones. Este documento también menciona un sistema de E / S basado en continuaciones que fue presentado por el grupo Yale Haskell pero que fue efímero.

Las mónadas se describen como la solución de Haskell para tratar con IO. Me preguntaba si había otras maneras de tratar con IO en lenguaje funcional puro.



La tipificación única se utiliza en Clean


Si por "puro" quiere decir "referencialmente transparente", es decir, que una función aplicada es libremente intercambiable con su resultado evaluado (y por lo tanto que llamar a una función con los mismos argumentos tiene el mismo resultado cada vez), cualquier concepto de I con estado está prácticamente excluido por definición.

Hay dos estrategias aproximadas de las que soy consciente:

  • Deje que una función haga IO, pero asegúrese de que nunca se pueda invocar dos veces con los mismos argumentos; esto da un paso al frente al dejar que las funciones sean trivialmente "referencialmente transparentes".

  • Trate todo el programa como una función pura y única tomando "todas las entradas recibidas" como argumento y devolviendo "todos los resultados producidos", ambos representados por alguna forma de flujo diferido para permitir la interactividad.

Hay una variedad de formas de implementar ambos enfoques, así como cierto grado de solapamiento, por ejemplo, en el segundo caso, las funciones que operan en las secuencias de E / S tienen pocas probabilidades de ser llamadas dos veces con la misma parte de la secuencia. Qué forma de verlo tenga más sentido depende del tipo de soporte que el lenguaje le brinde.

En Haskell, IO es un tipo de mónada que automáticamente enhebra estado secuencial a través del código (similar a la mónada de State funcionalmente pura), de modo que, conceptualmente, cada llamada a una función por lo demás impura obtiene un valor diferente del "estado implícito del mundo exterior".

El otro enfoque popular que conozco usa algo así como tipos lineales para un fin similar; asegurando que las funciones impuras nunca obtengan los mismos argumentos dos veces al tener valores que no pueden copiarse o duplicarse, de modo que los viejos valores del "estado del mundo exterior" no puedan mantenerse y reutilizarse.


La Programación Funcional Imperativa de Peyton Jones y Wadler es una lectura obligada si le interesa la IO funcional. Los otros enfoques que discuten son:

  • Diálogos que son flujos perezosos de respuestas y solicitudes

type Dialogue = [Response] -> [Request]

main :: Dialogue

  • Continuaciones: cada operación de IO toma una continuación como argumento

  • Tipos lineales: el sistema de tipos lo restringe de una manera que no puede copiar o destruir el estado externo, lo que significa que no puede llamar a una función dos veces con el mismo estado.