我正在阅读https://wiki.haskell.org/Do_notation_considered_harmful并惊讶地读到以下行
新来的人可能会认为语句的顺序决定了执行的顺序。。。语句的顺序也不是评估顺序的标准。
维基上的文章给出了一些例子来证明这个特性。虽然这些例子有道理,但我仍然不完全相信这个说法是真的,因为如果我写一些类似的东西
main = do
putStrLn "foo"
putStrLn "bar"
putStrLn "baz"
这三行按语句的顺序排列。那么这里到底发生了什么呢?
它说的是语句的顺序不会影响评估标准。正如@chi在IO中指出的那样,monad效应是按顺序排列的,但它们的评估顺序仍然未知。monad的一个例子将使概念变得清晰:
test = do
x <- Just (2 + undefined)
y <- Nothing
return (x + y)
在ghci:中
λ> test
Nothing
上面的代码有三条语句。它可以脱糖成以下形式:
Just (2 + undefined) >>= x -> Nothing >>= y -> return (x + y)
现在,由于(>>=)
是关联的,它的评估方式如下:
(Just (2 + undefined) >>= x -> Nothing) >>= y -> return (x + y)
注意,Maybe
monad的定义如下:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= _ = Nothing -- A failed computation returns Nothing
(Just x) >>= f = f x -- Applies function f to value x
将值(2 + undefined)
应用于函数x -> Nothing
将产生Nothing
。表达式2 + undefined
是未求值的,这要归功于Haskell遵循的惰性求值策略。
现在我们有一个简化的形式:
Nothing >>= y -> return (2 + undefined + y)
查看它的Monad
实例,您可以看到这将生成Nothing
,因为Nothing >>= _ = Nothing
。如果论点是严格的呢:
test = do
!x <- Just (2 + undefined)
y <- Nothing
return (y + x)
ghci
:演示
λ> test
*** Exception: Prelude.undefined
如果我们遵循严格的评估程序,那么你可以看到顺序实际上很重要。但在懒惰的环境中,语句的顺序并不重要。因此,维基声称,"语句的顺序不是评估顺序的标准"。