并没有什么特别的魔力do
符号。
main = do
return (trace "debug message 1" ())
trace "debug message 2" (return ())
与
main = return (trace "debug message 1" ()) >>=
\_ -> trace "debug message 2" (return ())
根据单子恒等律之一,return a >>= f = f a
, so
main = (\_ -> trace "debug message 2" (return ()))
(trace "debug message 1" ())
该函数忽略其参数,因此不计算该参数;表达式简化为
main = trace "debug message 2" (return ())
第一条消息完全消失了,你可以看到剩下的trace
现在是必须减少评估的最外层应用程序main
,因此将打印此消息。
当你翻转订单时,你得到了
main = do
trace "debug message 2" (return ())
return (trace "debug message 1" ())
这与
main = trace "debug message 2" (return ()) >>=
(\_ -> return (trace "debug message 1" ()))
这里的情况有点复杂。首先trace
(消息2)是被迫的,因为>>=
for IO
其左操作数是严格的。然后return ()
被执行,什么也不做。它的值被忽略,最后的动作,return (trace "debug message 1" ())
被执行。这也没有任何作用(return
never做任何有趣的事情)。自年底以来main
action 是程序的结束,这个返回值永远不会被检查,因此永远不会被强制,所以它不会被评估。有些人认为main
应该要求有类型IO ()
强调它的返回值从未被使用。 (我相信他们对此是错误的,因为永远运行的程序确实应该具有类型IO Void
or IO a
,但这是一个挑剔。)