IO Monad在什么意义上纯粹?

kei*_*ter 50 io monads haskell

我已经将IO monad描述为状态monad,状态是"现实世界".这种IO方法的支持者认为,这使IO操作变得纯粹,就像在引用透明时一样.这是为什么?从我的角度来看,IO monad中的代码似乎有很多可观察到的副作用.此外,是不是可以描述几乎任何非纯函数,如现实世界的功能?例如,我们不能想到,比方说,C的malloc是一个函数,它接受一个RealWorld和一个Int并返回一个指针和一个RealWorld,就像在Realmonorld隐含的IO monad中一样?

注意:我知道monad是什么以及它是如何使用的.请不要回复随机monad教程的链接,除非它专门解答我的问题.

mok*_*kus 57

我认为我听到的最好的解释实际上是最近的SO. IO Foo是一个创建一个Foo.另一个常见的,更直接的说法是,它是一个"产生一个Foo"的程序.可以执行(多次)来创建Foo或模拟尝试.配方/程序的执行是我们最终想要的(否则,为什么要写一个?),但是IO我们的代码中的动作表示的是配方本身.

这个配方是一个纯粹的价值,与a纯粹的价值完全相同String.食谱可以合并和有趣的,有时是惊人的,方式处理,但许多方面,这些食谱可以组合(除了公然非纯unsafePerformIO,unsafeCoerce等等)都完全引用透明,确定性,以及所有不错的东西.由此产生的配方完全没有任何方式取决于它所构建的配方以外的任何其他状态.

  • "食谱" - 很好的教学词. (7认同)
  • @luqui"教学法" - 关于学习阅读你的评论的好话 (4认同)

Dar*_*rio 16

此外,是不是可以描述几乎任何非纯函数,如现实世界的功能?例如,我们不能想到,比方说,C的malloc是一个函数,它接受一个RealWorld和一个Int并返回一个指针和一个RealWorld,就像在Realmonorld隐含的IO monad中一样?

当然 ...

函数式编程的整个概念是将程序描述为构成更大计算的小型独立计算的组合.

通过这些独立计算,您将获得许多好处,从简洁的程序到高效且可高效的可并行化代码,懒惰到控制按预期流动的严格保证 - 不会干扰或损坏任意数据.

现在 - 在某些情况下(如IO),我们需要不纯的代码.涉及此类操作的计算不能独立 - 它们可能会改变另一个计算的任意数据.

关键是 - Haskell 总是纯粹的,IO不会改变这一点.

所以,我们不纯的,非独立的代码必须得到一个共同的依赖 - 我们必须传递一个RealWorld.因此,无论我们想要运行什么状态计算,我们都必须传递这个RealWorld东西来应用我们的更改 - 而其他任何有状态计算想要查看或进行更改也必须知道RealWorld.

无论是通过IOmonad 明确地还是隐式地完成这都是无关紧要的.您将Haskell程序构建为一个转换数据的巨型计算,并且该数据的一部分是RealWorld.

main :: IO ()当你的程序以当前的真实世界作为参数运行时,初始化被调用,这个真实的世界将通过所有不纯的计算进行调用,就像数据在a中一样State.这就是monadic >>=(bind)照顾的东西.

并且其中RealWorld没有得到(如纯计算或没有任何>>=-ing到main),也没有做任何事的机会.它确实得到了,这是通过纯函数传递(隐式)参数而发生的.这就是为什么

let foo = putStrLn "AAARGH" in 42
Run Code Online (Sandbox Code Playgroud)

绝对没有 - 为什么IOmonad - 像其他任何东西一样 - 是纯粹的.在这段代码中发生的事情当然可能是不纯的,但它全都陷入了内部,没有机会干扰非连接的计算.

  • **内容**不纯; 容器不是 - "IO"monad的值与任何其他数据一样.并且你没有机会从"IO a"中获取内容(没有欺骗性地作弊) - 因此无论做出什么不纯的操作,它都被困在"IO"中. (9认同)
  • 但是如果IO monad的内容可能不纯,那么组成不纯行为的结果怎么可能是纯粹的呢?你没有任何意义. (3认同)

yai*_*chu 10

假设我们有类似的东西:

animatePowBoomWhenHearNoiseInMicrophone :: TimeDiff -> Sample -> IO ()
animatePowBoomWhenHearNoiseInMicrophone
    levelWeightedAverageHalfLife levelThreshord = ...

programA :: IO ()
programA = animatePowBoomWhenHearNoiseInMicrophone 3 10000

programB :: IO ()
programB = animatePowBoomWhenHearNoiseInMicrophone 3 10000
Run Code Online (Sandbox Code Playgroud)

这是一个观点:

animatePowBoomWhenHearNoiseInMicrophone是一个纯粹的功能,它的结果是相同的输入,programA并且programB完全相同.你可以做main = programA或者main = programB它会完全一样.

animatePowBoomWhenHearNoiseInMicrophone是一个接收两个参数并导致程序描述的函数.如果设置main为Haskell运行时或者将其包含在mainvia绑定中,则Haskell运行时可以执行此描述.

什么是IOIO是用于描述命令式程序的DSL,以"pure-haskell"数据结构和函数编码.

"complete-haskell"又名GHC是"pure-haskell"的实现,也是IO解码器/执行器的必要实现.

  • `animatePowBoomWhenHearNoiseInMicrophone`可能是我见过的唯一最好的示例代码函数名.好好玩,先生. (4认同)

Tim*_*ews 8

它简单地归结为扩展平等:

如果你要打getLine两次电话,那么两个电话都会返回一次IO String,每次看起来外面看起来完全相同.如果你要编写一个函数来获取2 IO String秒并返回一个Bool信号来检测两者之间检测到的差异,则无法检测到任何可观察属性的任何差异.它无法询问任何其他函数它们是否相等,并且任何使用尝试>>=也必须返回IO所有在外部都是等同的东西.


Tom*_*vid 6

我让马丁·奥德斯基回答

IO monad不会使函数变纯。显而易见,这是不纯的。

听起来很清晰。