corazza
corazza

Reputation: 32334

Haskell laziness in list comprehensions

I wanted to take a sum of all even numbers <= 1000.

The following code:

sum [x | x <- [1..1000], even x] (I know it can be done with [2,4..1000], this is for practice)

reports that the sum is 250500.

However:

sum [x | x <- [1..], even x && x <= 1000]

never finished and has to be interrupted!

I thought that I could safely write [1..], which is an infinite list, because Haskell would not try to evaluate it.

Furthermore, I thought that it would simply start going x by x, checking them and adding them.

So why does the above fail to produce a result?

Upvotes: 3

Views: 886

Answers (1)

raymonad
raymonad

Reputation: 949

sum [x | x <- [1..], even x && x <= 1000]

translates to something like

sum (filter (\x -> even x && x <= 1000) [1..])

The range expression (or, desugared, enumFrom) continues to generate values and filter keeps discarding them (it doesn't know there'll never be another element that satisfies the predicate), but sum never gets to the end of the list, so it can't return a result. You want to stop evaluating the list as soon as you see the first value greater than 1000:

sum (takeWhile (<= 1000) $ filter even [1..])

Upvotes: 11

Related Questions