Crítica de que la mónada IO es vista como una mónada estatal que opera en el mundo

46

La IOmónada en Haskell a menudo se explica como una mónada estatal donde el estado es el mundo. Entonces, un valor de tipo IO amónada se ve como algo así worldState -> (a, worldState).

Hace algún tiempo leí un artículo (o una publicación de blog / lista de correo) que criticaba esta opinión y daba varias razones por las que no es correcta. Pero no puedo recordar ni el artículo ni las razones. ¿Cualquiera sabe?

Editar: El artículo parece perdido, así que comencemos a reunir varios argumentos aquí. Estoy comenzando una recompensa para hacer las cosas más interesantes.

Editar: El artículo que estaba buscando es Abordar el equipo incómodo: entrada / salida monádica, concurrencia, excepciones y llamadas en idioma extranjero en Haskell por Simon Peyton Jones. (Gracias a la respuesta de TacTics).

Petr Pudlák
fuente
1
¿Es este artículo (o esta versión anterior )?
Joachim Sauer
@JoachimSauer Gracias, también es un artículo interesante, pero no es el que estoy buscando. Ese se centró en el paradigma del estado del mundo.
Petr Pudlák
Fuera de mi cabeza, los comentarios aquí son un buen comienzo
Adam
1
¿Qué significa "mundo" en este contexto? Supongo que no significa "La Tierra". ¿Es algún tipo de alcance global? El autor que escribió esto se está vendiendo en corto. Si quiere confundir y aplastar simultáneamente el ego de sus lectores, debería llamarlo "El estado es el universo" o "El estado de Dios". Mundo. Pah! ¡Ustedes jóvenes no aspiran lo suficientemente alto en estos días!
GlenPeterson

Respuestas:

33

El problema IO a = worldState -> (a, worldState)es que si esto fuera cierto, podríamos demostrarlo forever (putStrLn "Hello") :: IO ay undefined :: IO aser iguales. Aquí está la prueba cortesía de dolio (2010, irc):

forever m
 =
m >> forever m
 =
fix (\r -> m >> r)
 = {definition of >> for worldState -> (a, worldState)}
fix (\r -> \w -> r (snd $ m w))

Lema: (\r w -> r (snd $ m w)) ⊥ = ⊥

(\r w -> r (snd $ m w)) ⊥
  =
\w -> ⊥ (snd $ m w))
  =
⊥ . snd . m
  =
⊥

Por lo tanto forever m = fix (\r -> \w -> r (snd $ m w)) = ⊥

En particular forever (putStrLn "Hello") = ⊥y por lo tanto forever (putStrLn "Hello")y undefinedson programas equivalentes. Sin embargo, claramente no deben considerarse programas equivalentes, en teoría o en la práctica.

Tenga en cuenta que este modelo es incorrecto incluso sin invocar concurrencia.

Russell O'Connor
fuente
77
¿Alguien se sorprende de que un programa no definitivo sea equivalente a undefinedla semántica pura de Haskell? ¡Se supone que diferentes ⊥s son indistinguibles en la semántica pura de Haskell! Pero cuando pensamos operativamente en nuestros programas, también queremos distinguir diferentes tipos de ⊥, incluso cuando IOno están involucrados; Me importa si mi programa está lanzando una excepción o ingresando un ciclo infinito, incluso si puede probar que son iguales al demostrar que ambos son ⊥. Sin embargo, eso no es realmente una contradicción.
Ben
3
Las denotaciones de ⊥ y [0,1 ..] son ​​distintas a pesar de que ambas son "sin terminación". La diferencia es que ⊥ denota cálculos no finales y no productivos, mientras que [0,1 ..] no termina pero es productivo. Esperamos que (forever (putStrLn "Hello")) tenga una denotación similar, no terminante pero productiva.
Russell O'Connor
1
Pero forever (putStrLn "Hello")no es como [0,1..], seguramente. Su prueba no es particular worldState, por lo tanto, también se aplica a la mónada estatal regular. Entonces forever (someModificationWith "Hello")también es denotacionalmente equivalente a ⊥. No estoy completamente sorprendido por ese resultado; no es productivo en la semántica denotacional, y lo que la computadora está haciendo operacionalmente mientras esperamos para siempre es irrelevante. Lo mismo para forever (putStrLn "Hello"); no produce ni debería producir un nuevo estado mundial que de alguna manera podamos consumir perezosamente.
Ben
¿Están los lenguajes de programación como Mercury y Clean que utilizan el paso explícito del estado mundial para proporcionar un modelo declarativo para IO fundamentalmente incorrecto?
Ben
@Ben, ¿te refieres a cómo funciona el paso del mundo con la concurrencia? ¿Has visto el código rosetta para la concurrencia de Mercurio? Me he preguntado qué significa eso semánticamente también.
CMCDragonkai
12

Aquí hay una respuesta trivial: cualquier cambio en el estado de la mónada estatal se debe a cualquier acción ejecutada en la mónada. Si de hecho la explicación “WorldState -> (a, WorldState)” reclama la misma propiedad, con WorldState siendo un valor puro que solo cambia la mónada IO, está mal. Los cambios de hora, el contenido de los archivos, el estado de los controladores, etc. pueden cambiar independientemente de lo que ocurra en la mónada IO. Ese es el punto de la mónada IO. El hecho de que GHC pase por debajo de un valor RealWorld (o w / e lo era) es garantizar que las cosas se ejecuten en orden, por lo que sé, si eso (puede ser algo para poner en el valor ST).

Christopher Done
fuente
8
Eso en realidad no es un problema. puede modelar la operación de vinculación como realizar una modificación al estado mundial derivada de algún almacén de reglas fijo pero incognoscible.
sclv
1
@sclv: sí, pero esta tienda de reglas fija pero incognoscible es el factor diferenciador que hace que el IO no sea la mónada estatal, esta inconsistencia no se encuentra en la mónada estatal
Jimmy Hoffa
Un argumento que escuché contra el estado de WorldState está relacionado con la concurrencia, aunque no puedo recordar el argumento exacto. Pero aún así, supongo que WorldState también podría codificar el futuro, por lo que todavía no veo el problema. Por supuesto, supongo que me falta algo.
Thomas Eding
@JimmyHoffa: Sin embargo, puedes llevar la tienda de reglas en estado.
sclv
1
@JimmyHoffa: este es el propósito de la abstracción. Además, para seguir mi comentario inicial, Clean modela IO como un mundo que pasa explícita y felizmente, usando tipos únicos para garantizar que no engañes y "dupliques" el mundo. Esta es una forma de hacer cumplir la abstracción.
sclv
12

Escribí una publicación de blog sobre el tema de cómo modelar IO como una forma de rutina asimétrica que se comunica con el sistema de tiempo de ejecución para su idioma. (Es cierto que es la tercera parte de una serie)

http://comonad.com/reader/2011/free-monads-for-less-3/

Esa publicación cubre un poco de por qué es incómodo razonar sobre la semántica de 'pasar el mundo'.

Edward KMETT
fuente
¡+1 - especialmente interesante, ya que durante mucho tiempo he planeado implementar el IO del lenguaje que estoy diseñando de manera similar a esto! :)
Jules
8

Ver Tackling the Awkward Squad .

La gran razón es que los modelos de estado RealWorld de la mónada IO no funcionan bien con la concurrencia. SPJ en este clásico legible favorece el uso de una semántica operativa para entenderlo.

Táctica
fuente
Creo que este es el artículo original que estaba buscando, principalmente la sección 3.1. Si lo hubiera publicado antes de editar la pregunta, habría aceptado su respuesta, pero ahora creo que será más justo esperar hasta el final, para ver todas las ideas que otros publicarán.
Petr Pudlák
5

La principal queja sobre los modelos de estado de RealWorld es que, como dice TacTics, la transmisión mundial no necesariamente funciona con la concurrencia. Pero Wouter Swierstra y Thorsten Altenkirch mostraron cómo razonar sobre la concurrencia como un efecto "mundial", con una secuencia fija pero arbitraria de hilos entrelazados en su artículo "La bella en la bestia: una semántica funcional para el escuadrón torpe": http : //www.staff.science.uu.nl/~swier004/Publications/BeautyInTheBeast.pdf

El código correspondiente a esto está en Hackage como IOSpec: http://hackage.haskell.org/package/IOSpec

Creo que la tesis de Wouter entra en más detalles: http://www.staff.science.uu.nl/~swier004/Publications/Thesis.pdf

sclv
fuente