IO Monad纯粹是什么意思?
我曾将IO monad描述为国家单体,其中国家是“真实的世界”。 这种IO方法的支持者认为,这使得IO操作是纯粹的,就像在透明方面一样。 这是为什么? 从我的角度来看,IO monad中的代码有很多可观察到的副作用。 另外,难道不能像真实世界的函数那样描述任何非纯函数吗? 例如,我们不能把C的malloc想象成一个函数,它需要一个RealWorld和一个Int并且返回一个指针和一个RealWorld,就像RealWorld隐含的IO monad一样?
注意:我知道单子是什么以及它是如何使用的。 请不要回应一个随机monad教程的链接,除非它特别强调我的问题。
我认为我听到的最好的解释实际上是最近在SO上。 IO Foo
是创建Foo
的配方。 另一种常见的,更直接的说法是,它是一个“产生Foo
程序”。 它可以被执行(很多次)来创建一个Foo
或死掉尝试。 配方/程序的执行是我们最终想要的(否则,为什么要写一个?),但是在我们的代码中由IO
操作表示的东西就是配方本身。
这个配方是一个纯粹的价值,就像String
是一个纯粹的价值一样。 食谱可以用有趣的,有时令人惊讶的方式进行组合和操作,但是这些食谱可以组合使用的许多方式(除了明显不纯的unsafePerformIO
, unsafeCoerce
等)都是完全透明的,确定性的以及所有这些东东。 由此产生的食谱完全不以任何方式取决于它所建立的食谱以外的任何状态。
另外,难道不能像真实世界的函数那样描述任何非纯函数吗? 例如,我们不能把C的malloc想象成一个函数,它需要一个RealWorld和一个Int并且返回一个指针和一个RealWorld,就像RealWorld隐含的IO monad一样?
当然 ...
函数式编程的全部概念是将程序描述成构建更大计算的小型独立计算的组合。
有了这些独立的计算,您将获得很多好处,从简洁的程序到高效且高效的可并行编码,懒惰直到控制按预期流动的严格保证 - 不会有任何干扰或破坏任意数据的可能性。
现在 - 在某些情况下(如IO),我们需要不纯的代码。 涉及这些操作的计算不能独立 - 它们可能会改变另一个计算的任意数据。
关键是 - Haskell总是纯粹的, IO
不会改变这一点。
所以,我们不纯的,非独立的代码必须得到一个共同的依赖 - 我们必须通过一个RealWorld
。 因此,无论我们想要运行哪种有状态的计算,我们都必须通过这个RealWorld
来应用我们的修改 - 而且任何其他有状态的计算想要看到或进行更改也必须知道RealWorld
。
无论是通过IO
monad显式还是隐式完成都是无关紧要的。 您将Haskell程序构建为一个可以转换数据的巨大计算,其中一部分数据是RealWorld
。
一旦当你的程序以当前真实世界作为参数运行时,初始main :: IO ()
被调用,这个真实世界就会通过所有不纯的计算来进行,就像数据在一个State
。 这就是monadic >>=
照顾的事情。
而RealWorld
没有得到的地方(如在纯粹的计算中或者没有任何>>=
-ing到main
),没有任何处理它的机会。 并且在哪里得到,这是通过纯功能传递(隐式)参数而发生的。 这就是为什么
let foo = putStrLn "AAARGH" in 42
完全没有 - 为什么IO
单元 - 像其他任何东西 - 都是纯粹的。 这段代码里面发生的事情当然可能是不纯的,但它全部被捕获,不会干扰非连接的计算。
假设我们有这样的东西:
animatePowBoomWhenHearNoiseInMicrophone :: TimeDiff -> Sample -> IO ()
animatePowBoomWhenHearNoiseInMicrophone
levelWeightedAverageHalfLife levelThreshord = ...
programA :: IO ()
programA = animatePowBoomWhenHearNoiseInMicrophone 3 10000
programB :: IO ()
programB = animatePowBoomWhenHearNoiseInMicrophone 3 10000
这是一个观点:
animatePowBoomWhenHearNoiseInMicrophone
是在这个意义上,其结果为同一个输入,一个纯函数programA
和programB
,是完全一样的。 你可以做main = programA
main = programB
或main = programB
,它会完全一样。
animatePowBoomWhenHearNoiseInMicrophone
是一个接收两个参数并导致程序描述的函数。 Haskell运行时可以执行此描述,如果您将main
设置为main
或以其他方式将其包含在main
通过绑定中。
什么是IO
? IO
是描述命令式程序的DSL,用“纯哈斯克尔”数据结构和函数编码。
“complete-haskell”又名GHC是“pure-haskell”的实现,也是IO
解码器/执行器的必要实现。