I'm learning haskell and I have the following code:
fib a b =
a : fib b (a + b)
findFibSum =
sum [x | x <- fib 1 2, mod x 2 == 0 && x < 100]
If I run findFibSum
nothing happens, it just sits there. Shouldn't fib
be evaluated and return each item? I'm guessing this has something to do with lazy evaluation.
If I call take
first and make findFibSum
accept the taken list like:
findFibSum $ take 100 $ fib 1 2
it works instead. How do I make it so that I can retrieve and check each item instead? I can probably get away by taking by batch using take
but I'd like to understand this first.
UPDATE
Thanks to @amalloy i finally got it working with:
findFibSum xs =
sum [x | x <- takeWhile (<4000000) xs, mod x 2 == 0]
takeWhile
ensures that it'll stop retrieving value from fib once it gets >= 4m.
Consider the simpler problem of summing the first 100 positive integers:
This doesn't work either. As a human, you know that once
x <= 100
returns False, it will never return True again, becausex
is getting larger. But Haskell doesn't know that! So this list comprehension produces the first 100 integers, then tries 101 and finds it doesn't work, then tries 102 and finds it doesn't work...there's no point at whichsum
can be sure there are no more elements in the list, so it can never return a number for you.Your list comprehension over
fib 1 2
has the same problem. You can resolve it by callingtake
ortakeWhile
separately, instead of using a guard on each element, as you demonstrate in your question.