17

我只是在学习 Haskell 和 IO 单子。我想知道为什么不强制程序输出“hi”和“bye”:

second a b = b
main = print ((second $! ((print "hi") >>= (\r -> return ()))) "bye")

据我了解,$!操作员将强制计算的第一个参数second,并且>>=操作员需要运行print "hi"才能从中获取一个值并将其传递给\r -> return (),这将在屏幕上打印“hi”。

我的推理有什么问题?

而且,有没有办法证明 Haskell 不能被欺骗(除了使用不安全的函数)在“安全”代码中运行 IO 操作?

4

2 回答 2

34

您强制的表达式是((print "hi") >>= (\r -> return ())),它的类型是IO ()。因此,它代表一个 IO 操作。但是评估这样的事情与运行它是完全不同的!

评估一个值意味着执行足够的步骤将其转换为所谓的弱头范式。因为IO是抽象的,所以在这种情况下要理解它的含义有点棘手,但是可以将其IO a视为RealWorld -> (a, RealWorld),然后弱头范式就是一个等待被赋予的函数RealWorld

运行意味着评估,但也将RealWorld作为参数传递,从而导致IO效果发生。

所有这些都不是很具体IO;您的困惑和概念同样适用于a -> b. 如果您了解$!当第二个参数是函数时会发生什么,您就会了解当它是 IO 操作时会发生什么。

于 2014-07-16T08:25:40.950 回答
21

您将评估执行混淆了。当您强制使用类似 的表达式print "hi"时,不会打印任何内容。它只是产生一个值(在这种情况下,一个 type 的值IO())表示打印出某些东西的动作。您可以将值print "hi"视为打印“hi”的方法。

于 2014-07-16T08:26:28.513 回答