潜入monad后,我明白它们是允许在某些上下文中链接计算的一般概念(失败,非确定性,状态等),并且它们背后没有任何魔力 .
IO monad感觉即使不是魔术,但特别 .
-
你无法像其他monad一样逃脱IO monad
-
IO动作只能由
main
函数运行 -
IO始终位于monad变换器链的底部
IO monad的 -
实现尚不清楚,源代码显示了一些Haskell内部
上述观点的原因是什么?是什么让IO如此特别?
Update :在纯代码评估顺序中无关紧要 . 但是在做IO时这很重要(我们希望在我们阅读之前保存客户) . 根据我的理解,IO monad为我们提供了这样的订购保证 . 它是一般monad的属性还是IO monad特有的东西?
2 回答
我不确定你的“逃避”是什么意思 . 如果你的意思是,以某种方式展开monadic值的内部表示(例如list - > cons-cells序列) - 这是一个实现细节 . 实际上,您可以在很多全局可用数据上定义an IO emulation in pure Haskell - 基本上只是
State
. 那将具有IO
的所有语义,但实际上没有与现实世界交互,只有它的模拟 .如果你的意思是,你可以从monad - nope中“提取值”,'s not in general possible, even for most pure-haskell monads. For instance, you can' t从
Maybe a
(可能是Nothing
)或Reader b a
中提取一个值(如果b
无人居住怎么办?)嗯,从某种意义上说,一切都只能由
main
函数来运行 . 从main
以某种方式调用的代码只会坐在那里,你可以用_3041835替换它而不改变任何东西 .没错,但例如情况也是如此 .
ST
.再说一次:实现只是一个实现细节 .
IO
实施的复杂性实际上与高度优化有很大关系;对于专门的纯单子(例如attoparsec)也是如此 .As I already said),更简单的实现是可能的,它们不会像完全成熟的优化现实世界
IO
类型那样有用 .幸运的是,实施不必真的打扰你;
IO
的内部可能不清楚,但外部,实际的monadic界面,非常简单 .首先 - 评估顺序在纯代码中很重要!
但实际上,由于错误的纯代码评估,你永远不会得到错误的非⊥结果 . 这实际上不适用于重新排序monadic动作(
IO
或其他),因为更改序列顺序会更改结果操作的实际结构,而不仅仅是运行时将用于构造此结构的评估顺序 .例如(list monad):
所有这一切,肯定
IO
是非常特别的,事实上我认为有些人会犹豫称它为monad(它实际上应该是IO
来实现monad法则) . 特别是,懒惰IO是一个巨大的麻烦制造者(最好在任何时候都避免) .可以对
ST
monad进行类似的陈述,或者可以说是STM
monad(尽管你可以在IO
之上实际实现那个) .基本上像Reader monad,Error monad,Writer monad等等,都只是纯粹的代码 .
ST
和IO
monad是唯一确实存在不纯物质的状态(状态变异等),所以它们在纯Haskell中无法定义 . 它们必须是"hard-wired"进入编译器的某个地方 .