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

时间:2015-03-07 00:44:41

标签: haskell monads do-notation

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

  

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

wiki帖子提供了一些演示此属性的示例。虽然这些例子是有道理的,但我仍然不完全相信这句话是真的,因为如果我写的话就像

main = do
  putStrLn "foo"
  putStrLn "bar"
  putStrLn "baz"

这三行按照陈述的顺序排列。那究竟发生了什么?

1 个答案:

答案 0 :(得分:6)

它所说的是陈述的顺序不会影响评估标准。正如@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

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