简体   繁体   English

Haskell中列表理解的评估

[英]Evaluation of list-comprehensions in Haskell

I am wondering exactly how list-comprehensions are evaluated in Haskell. 我确切地想知道在Haskell中如何评估列表综合。 After reading this Removing syntactic sugar: List comprehension in Haskell and this: Haskell Lazy Evaluation and Reuse I still don't really understand if 阅读完《 删除语法糖》之后:在Haskell中理解列表,以及以下内容: Haskell懒惰的评估和重用我还是不太了解

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

is actually exactly equivalent (not just in outcome but in evaluation) to 实际上完全等效(不仅在结果上,而且在评估上)

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

and if so, does this mean it can potentially reduce time complexity drastically to build up the desired list with only desired elements? 如果是的话,这是否意味着可以仅使用所需元素来显着降低所需列表的时间复杂度? Also, how does this work in terms of infinite lists? 此外,这在无限列表方面如何工作? To be specific: I assume something like: 具体来说:我假设类似:

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

will be evaluated in finite time, but how "obvious" does the fact that there are no more elements above some value which satisfy the predicate need to be, for the compiler to consider it? 将在有限时间内进行评估,但是在编译器考虑的前提下,没有更多的元素满足谓词的值,这个事实有多“明显”呢? Would

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

work (see project Euler problem 34 https://projecteuler.net/problem=34 ). 工作(请参阅项目Euler问题34 https://projecteuler.net/problem=34 )。 There is obviously an upper bound because from some x on x*9! 显然有一个上限,因为从x * 9上的x开始! < 10^n -1 always holds, but do I need to supply that bound or will the compiler find it? <10 ^ n -1始终成立,但是我需要提供该界限吗?还是编译器会找到它?

There's nothing obvious about the fact that a particular infinite sequence has no more elements matching a predicate. 一个特定的无限序列不再有与谓词匹配的元素这一事实并没有显而易见的事实。 When you pass a list to filter , it has no way of knowing any other properties of the elements than that an element can be passed to the predicate. 当您将列表传递给filter ,除了可以将元素传递给谓词之外,它无法知道元素的任何其他属性。

You can write your own version of Ord a => List a which can describe a sequence as ascending or not, and a version of filter that can use this information to stop looking at elements past a particular threshold. 您可以编写自己的Ord a => List a版本, Ord a => List a版本可以描述一个序列是否升序,以及可以使用此信息停止查看超过特定阈值的元素的filter版本。 Unfortunately, list comprehensions won't use either of them. 不幸的是,列表理解将不会使用它们中的任何一个。

Instead, I'd use a combination of takeWhile and a comprehension without a predicate / a plain map . 相反,我会结合使用takeWhile和不带谓词/纯map的理解。 Somewhere in the takeWhile arguments, you will supply the compiler the information about the expected upper bound; takeWhile参数中的takeWhile ,您将向编译器提供有关预期上限的信息; for a number of n decimal digits, it would be 10^ n . 对于n个十进制数字,它将是10 ^ n

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

should always evaluate to the same result as 应始终计算相同的结果,

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

However, there is no guarantee that this is how the compiler will actually do it. 但是, 不能保证编译器将实际执行此操作。 The section on list comprehensions in the Haskell Report only mentions what list comprehensions should do, not how they should work. 在Haskell的报告列表理解的部分只提到什么列表内涵应该做的,他们不应该是如何工作的。 So each compiler is free to do as its developers find best. 因此,每个编译器都可以自由地按照开发人员的最佳状态来做。 Therefore, you should not assume anything about the performance of list comprehensions or that the compiler will do any optimizations. 因此,您不应假设任何有关列表推导的性能,否则编译器将进行任何优化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM