Haskell is as lazy as it can possibly be. It doesn't calculate any value that you don't ask it for, and if you do let nums = filter odd (map (^2) [1..])
you haven't forced it to calculate anything yet. For now it knows that nums
is of type Num a => [a]
(because of the types of the operations you've described) but it doesn't know anything else about it (and that's fine!)
Even when you run takeWhile (<10000)
you're not forcing any numbers. Now ghc knows that takeWhile (<10000) nums
has type (Ord a, Num a) => [a]
(you've introduced the additional typeclass when you compared by (<)
) but that's all it knows.
Even once you call sum
, ghc doesn't have to do anything. sum
expects a Num a => [a]
(technically a (Num a, Foldable t) => t a
but let's pretend those are the same thing for right now) and you've given it one. Until you actually ask for the result of that operation, ghc doesn't do anything. You can test this by doing let foobar = sum [1..]
in your interpreter. As long as you don't ever ask for the result of foobar
, Haskell is fine with that expression.
However, if you ever ask for that result, you've forced the whole line to compute. sum
needs its list, so it asks takeWhile (<10000)
for it. takeWhile
needs its list, so it asks filter odd
for it. filter
needs its list so it asks map (^2)
for it, but filter
doesn't need the whole list at a time, so map
still works as lazily as possible and gives each number one at a time.
Once takeWhile
has found a number (>=10000)
, it doesn't need anymore and happily hands off to sum
, which produces your result and ghc goes back to being lazy, not producing any more results of nums
unless you need them.