Le IO
monad à Haskell est souvent expliqué comme une monade d'état où l'État est le monde. Donc, une valeur de type IO a
Monad est considérée comme quelque chose comme worldState -> (a, worldState)
.
Il y a quelque temps, j'ai lu un article (ou un article de liste de blog/mailing) qui a critiqué ce point de vue et a donné plusieurs raisons pour lesquelles ce n'est pas correct. Mais je ne me souviens ni de l'article ni les raisons. Tout le monde sait?
Edit: L'article semble perdu, alors commençons donc à rassembler divers arguments ici. Je commence une prime à faire les choses plus intéressantes.
EDIT: L'article que je cherchais est S'attaquer à l'équipe gênante: entrée/sortie monadique, concurrence, exceptions et appels de langue étrangère à Haskell par Simon Peyton Jones . (Merci à la réponse de la tactique.)
Le problème avec IO a = worldState -> (a, worldState)
est que si cela était vrai, nous pourrions prouver que forever (putStrLn "Hello") :: IO a
et undefined :: IO a
Sont égaux. Voici la preuve de la permission 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))
Lemma: (\r w -> r (snd $ m w)) ⊥ = ⊥
(\r w -> r (snd $ m w)) ⊥
=
\w -> ⊥ (snd $ m w))
=
⊥ . snd . m
=
⊥
Par conséquent, forever m = fix (\r -> \w -> r (snd $ m w)) = ⊥
En particulier, forever (putStrLn "Hello") = ⊥
et donc forever (putStrLn "Hello")
et undefined
sont des programmes équivalents. Cependant, ils ne sont clairement pas censés être considérés comme des programmes équivalents, en théorie ou en pratique.
Notez que ce modèle est faux même sans invoquer la concurrence.
Voici une réponse triviale: toute modification de l'État de l'État monad est due à toutes les actions courues dans la monade. Si, en effet, l'explication "WorldState -> (a, Worldstate) affirme la même propriété, avec Worldstate étant une valeur pure que seuls les changements IO monad, c'est faux. Les changements de temps, le contenu des fichiers, l'état des poignées, etc. peuvent changer de manière indépendante de ce qui se passe dans la monade IO. C'est le point de la monade IO. Le fait que GHC passe autour d'une valeur de Realworld (ou d'une personne qui c'était) en dessous est de garantir que les choses sont courues dans l'ordre, autant que je sache, si cela (peut simplement être quelque chose à mettre à la valeur de la rue).
J'ai écrit un article de blog sur le sujet de la façon de modeler IO comme une forme de coroutine asymétrique communiquant avec le système d'exécution pour votre langue. (C'est certes la troisième partie d'une série)
http://comonad.com/reader/2011/free-monads-for-less-3/
Ce post couvre un peu pourquoi il est gênant de raisonner sur la sémantique du "passage mondial".
Voir S'attaquer à l'équipe maladroite .
La grande raison est Realworld State Modèles du IO monade ne fonctionne pas bien avec la concurrence. SPJ dans cette faveur classique lisible utilisant une sémantique opérationnelle pour la comprendre.
La principale plainte concernant les modèles d'État Realworld est que, comme la dit la tactique, le passage mondial ne fonctionne pas nécessairement avec la concurrence. Mais Wouter Swierstra et Thorsten Altenkirch ont montré comment raisonner sur la concurrence en tant qu'effet "de passage mondial", avec une séquence fixe mais arbitraire de threads entrelacés dans leur papier "Beauté dans la bête: une semitique fonctionnelle pour l'équipe gênante": http://www.staff.science.uu.nl/~swier004/publications/beautyinthebeast.pdf
Le code correspondant à cela est sur Hackage comme ISPEC: http://hackage.hakell.org/package/iospec
Je pense que la thèse de Wouter entre en détail: http://www.staff.science.uu.nl/~wier004/publications/thesis.pdf