评估Haskell中的列表推导

时间:2017-03-29 16:07:18

标签: haskell list-comprehension

我想知道在Haskell中如何评估list-comprehension。阅读此Removing syntactic sugar: List comprehension in Haskell之后:Haskell Lazy Evaluation and Reuse我仍然不明白是否

[<function> x|x <- <someList>, <somePredicate>]

实际上完全等同于(不仅仅是结果,而是评估中)

filter (<somePredicate>) . map (<function>) $ <someList>

如果是这样,这是否意味着它可以大大减少时间复杂度,以构建只有所需元素的所需列表? 此外,这如何在无限列表方面工作?具体来说:我假设像:

[x|x <- [1..], x < 20]

将在有限的时间内进行评估,但是对于编译器来说,在某些值上面没有更多元素满足谓词需要的事实是多么“明显”呢?将

[x|x <- [1..], (sum.map factorial $ digits x) == x]

工作(参见项目欧拉问题34 https://projecteuler.net/problem=34)。显然有一个上限,因为x * 9上有些x! &LT; 10 ^ n -1总是成立,但是我需要提供该绑定还是编译器会找到它?

2 个答案:

答案 0 :(得分:3)

特定的无限序列没有更多与谓词匹配的元素,这一事实并不明显。将列表传递给filter时,它无法知道元素的任何其他属性,而不能将元素传递给谓词。

您可以编写自己的Ord a => List a版本,可以将序列描述为升序与否,以及版本filter,可以使用此信息停止查看超过特定阈值的元素。不幸的是,列表推导不会使用其中任何一个。

相反,我使用takeWhile和没有谓词/普通map的理解的组合。在takeWhile参数中的某处,您将为编译器提供有关预期上限的信息;对于许多 n 十进制数字,它将是10 ^ n

答案 1 :(得分:3)

[<function> x|x <- <someList>, <somePredicate>]

应始终评估

相同的结果
filter (<somePredicate>) . map (<function>) $ <someList>

然而,无保证这就是编译器实际执行的方式。 The section on list comprehensions in the Haskell Report仅提及 列表推导应该做什么,而不是 应该如何工作。所以每个编译器都可以随意开发,因为它的开发人员最好。因此,您不应假设列表推导的性能或编译器将进行任何优化。