IO monad是什么意思(如果有的话)?

在深入monads之后,我明白他们是一个通用概念,允许在某些上下文(失败,非确定性,状态等)内链接计算,并且他们背后没有魔法。

即使不是魔法,但IO monad仍然感觉很特别。

  • 你不能像其他monad那样逃脱IO monad
  • IO操作只能由main函数运行
  • IO总是处于单变压器链的底部
  • IO monad的实现不清楚,源代码显示了一些Haskell内部
  • 以上几点的原因是什么? 什么让IO如此特别?

    更新 :纯代码评估顺序无关紧要。 但是在做IO时它确实很重要(我们在读取它之前要保存客户)。 据我所知,IO monad为我们提供了这样的订购保证。 它是一般monad的属性,还是IO monad特有的?


    你不能像其他monad那样逃脱IO monad

    我不确定你的意思是“逃脱”。 如果你的意思是以某种方式解开一元值的内部表示(例如list - > cons-cells序列) - 那就是一个实现细节。 事实上,你可以在纯Haskell中定义一个IO仿真 - 基本上只是一个State遍布全球的数据。 这将具有IO所有语义,但是实际上没有与真实世界交互,只是模拟它。

    如果你的意思是,你可以从monad中“提取数值” - 这是不可能的,即使对于大多数纯哈斯克尔单子来说也是如此。 例如,你不能从Maybe a (可能是Nothing )或Reader ba提取一个值(如果b无人居住,该怎么办?)

    IO操作只能由main函数运行

    那么,从某种意义上说,一切只能由main功能来运行。 不以某种方式从main调用的代码只会在那里存在,您可以用undefined替换而不更改任何内容。

    IO总是处于单变压器链的底部

    确实如此,但ST也是如此。

    IO monad的实现不清楚,源代码显示了一些Haskell内部

    再次说明:实现就是一个实现细节。 IO实现的复杂性实际上与高度优化有很大关系; 专门的纯单子也是如此(例如attoparsec)。

    正如我已经说过的),更简单的实现是可能的,它们不会像成熟的优化的真实世界IO类型那样有用。

    幸运的是,实施并不需要真的打扰你; IO的内部可能不清楚,但外部的实际一元接口非常简单。

    在纯代码评估顺序中并不重要

    首先 - 评估顺序可以在纯代码中起作用!

    Prelude> take 10 $ foldr (h t -> h `seq` (h:t)) [] [0..]
    [0,1,2,3,4,5,6,7,8,9]
    Prelude> take 10 $ foldr (h t -> t `seq` (h:t)) [] [0..]
    ^CInterrupted.
    

    但是,由于错误的纯代码评估,事实上你永远不会得到错误的非⊥结果。 这实际上并不适用于重新排序monadic动作( IO或其他),因为改变序列顺序改变了结果动作的实际结构,而不仅仅是运行时将用来构造该结构的评估顺序。

    例如(list monad):

    Prelude> [1,2,3] >>= e -> [10,20,30] >>= z -> [e+z]
    [11,21,31,12,22,32,13,23,33]
    Prelude> [10,20,30] >>= z -> [1,2,3] >>= e -> [e+z]
    [11,12,13,21,22,23,31,32,33]
    

    尽管如此, IO的确是非常特殊的,我认为有些人毫不犹豫地称之为单子(实际上它应该表示IO实现单子法的含义有点不清楚)。 尤其懒惰的IO是一个巨大的麻烦制造者(并且最好在任何时候都避免)。


    可以对ST monad或者STM monad做类似的声明(尽管你可以在IO之上实现)。

    基本上像Reader monad,Error monad,Writer monad等等,都只是纯代码。 STIO monad是唯一真正做不纯的事情(状态变异等),所以它们在纯粹的Haskell中是不可定义的。 它们必须在某处“编译”到编译器中。

    链接地址: http://www.djcxy.com/p/80875.html

    上一篇: In what sense is IO monad special (if at all)?

    下一篇: Functional implementation (e.g. in Haskell) of GoF's Lexi Editor application