在do块中执行的顺序是否真的不依赖于语句顺序?

XrX*_*rXr 1 monads haskell do-notation

我正在阅读https://wiki.haskell.org/Do_notation_considered_harmful并惊讶于阅读以下内容

新手可能会认为陈述的顺序决定了执行的顺序.......陈述的顺序也不是评估顺序的标准.

维基文章给出了一些展示这个属性的例子.虽然这些例子很有意义,但我仍然不完全相信这个陈述是正确的,因为如果我写的是这样的话

main = do
  putStrLn "foo"
  putStrLn "bar"
  putStrLn "baz"
Run Code Online (Sandbox Code Playgroud)

这三行按照陈述的顺序排列.那到底是怎么回事?

Sib*_*ibi 6

它所说的是,陈述的顺序不会影响评估标准.正如@chi指出的那样,IO monad效应按顺序排序,但它们的评估顺序仍然未知.monad的一个例子,它将使概念清晰:

test = do
  x <- Just (2 + undefined)
  y <- Nothing
  return (x + y)
Run Code Online (Sandbox Code Playgroud)

在ghci:

?> test
Nothing
Run Code Online (Sandbox Code Playgroud)

上面的代码有三个陈述.它可以脱糖成下列形式:

Just (2 + undefined) >>= \x -> Nothing >>= \y -> return (x + y)
Run Code Online (Sandbox Code Playgroud)

既然(>>=)是左关联的,它将被评估为:

(Just (2 + undefined) >>= \x -> Nothing) >>= \y -> return (x + y)

请注意,Maybemonad的定义如下:

(>>=) :: 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
Run Code Online (Sandbox Code Playgroud)

将值(2 + undefined)应用于该函数\x -> Nothing将导致Nothing.2 + undefined由于Haskell遵循惰性评估策略,表达式未被评估.

现在我们有一个缩小的形式:

Nothing >>= \y -> return (2 + undefined + y)
Run Code Online (Sandbox Code Playgroud)

Monad查看它的实例,你可以看到这将产生Nothing因为Nothing >>= _ = Nothing.如果争论是严格的,那该怎么办:

test = do
  !x <- Just (2 + undefined)
  y <- Nothing
  return (y + x)
Run Code Online (Sandbox Code Playgroud)

演示ghci:

?> test
*** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)

如果我们遵循严格的评估程序,那么您可以看到订单确实很重要.但在懒惰的环境中,陈述的顺序无关紧要.因此维基声称,"声明的顺序不是评估顺序的标准".