简体   繁体   中英

Evaluation of list-comprehensions in Haskell

I am wondering exactly how list-comprehensions are evaluated in 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

[<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 ). There is obviously an upper bound because from some x on x*9! < 10^n -1 always holds, but do I need to supply that bound or will the compiler find it?

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.

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. 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 . Somewhere in the takeWhile arguments, you will supply the compiler the information about the expected upper bound; for a number of n decimal digits, it would be 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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