1

我正在阅读https://wiki.haskell.org/Do_notation_considered_harmful并惊讶地阅读以下几行

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

wiki 帖子提供了一些示例来演示此属性。虽然这些例子是有道理的,但我仍然不完全相信这个陈述是真的,因为如果我写了类似的东西

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

这三行按语句的顺序出现。那么这里到底发生了什么?

4

1 回答 1

6

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

请注意,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

将值(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

如果我们遵循严格的评估程序,那么您可以看到顺序实际上很重要。但是在惰性设置中,语句的顺序并不重要。因此维基声称,“陈述的顺序不是评估顺序的标准”。

于 2015-03-07T01:31:36.843 回答