Haskell:无限列表 - Haskell多么懒惰?

时间:2016-01-05 18:05:38

标签: haskell

Haskell多么懒惰?

为什么以下不知道何时停止?

sum ([n^2 | n <- [1..], odd (n^2), n^2 < 100])

3 个答案:

答案 0 :(得分:12)

这不是关于它是多么懒惰,而是它是否有任何方式可以知道n^2 < 100一旦它是假的,它将永远不再是真的。它没有。

数组理解的这些部分是过滤器表达式,而不是停止条件

答案 1 :(得分:7)

仅仅因为11 ^ 2超过100并不意味着13 ^ 2超过100.嗯......好吧,确实如此,但GHC应该如何解决这个问题呢?它是一个编译器,而不是任意数学真理的证明者。

答案 2 :(得分:2)

你给出的表达有效地消解了:

sum $ do
    n <- [1..]
    _ <- if odd (n^2) then [()] else []
    _ <- if n^2 < 100 then [()] else []
    return (n^2)

如果您从未见过List monad,那么这似乎是一种使用do的奇怪方式,但它最终变为:

sum $ concatMap (\n -> if odd (n^2) && (n^2 < 100) then [n^2] else []) [1..]

其中concatMap位于Prelude中(在早期版本中,您可以将其定义为(concat .) . map,但现在它适用于任何Foldable,而不仅仅是列表,因此更接近{{ 1}})。

现在关键是当Haskell看到这个功能时它会停止分析!计算机科学的一个定理是,证明任意一般函数属性的唯一一般方法是运行它们--Haskell不会窥视内部,也不会给(concat .) . fmap任何方式来查看内部,一个函数来尝试确定它是否最终会为所有进一步的输入产生concatMap

计算机 dumb ,这是:程序越聪明,就越难以在脑中建模。 []是一个非常愚蠢的函数,它只是将函数参数应用于列表的每个元素,并将它们与concatMap一起放在一起,就是这样。列表推导是列表monad的concat表示法的非常愚蠢的语法替换,这就是他们所做的一切。 do符号只是do类型类中>>=函数的非常愚蠢的语法替换,对于列表是Monad。因为所有这些都非常愚蠢,你可以很容易地理解所有这些事情。