我正在学习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"码?
答案 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”的配方。