为什么不能通过严格的评估来欺骗Haskell执行IO操作?

时间:2014-07-16 08:12:39

标签: haskell monads io-monad

我正在学习Haskell和IO monads。我想知道为什么这不会强迫程序输出"嗨"以及" bye":

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

据我了解,$!运算符会强制评估second的第一个参数,>>=运算符需要按顺序运行print "hi"从中获取价值并将其传递给\r -> return (),这将打印" hi"到了屏幕。

我的推理出了什么问题?

而且,有没有什么方法可以证明Haskell不能被欺骗(除了使用不安全的函数)在内部运行IO操作" safe"码?

2 个答案:

答案 0 :(得分:33)

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

评估值意味着执行足够的步骤将其转换为所谓的weak head normal form。因为IO是抽象的,在这种情况下看到这意味着什么有点棘手,但是人们可以将IO a视为RealWorld -> (a, RealWorld),然后弱头正常形式是,一个等待RealWorld的函数。

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

这一切并非针对IO;您的困惑和概念同样适用于a -> b。如果你理解第二个参数是一个函数时$!做了什么,你就会明白当它是一个IO动作时会发生什么。

答案 1 :(得分:21)

您将评估执行混淆。强制使用print "hi"之类的表达式时,不会打印任何内容。它只生成一个值(在这种情况下,类型为IO()的值),表示打印出来的操作。您可以将print "hi"的值视为打印“hi”的配方。