appendix B Lazy evaluation

 

Haskell does not strictly evaluate its values but uses lazy evaluation. The short explanation of lazy evaluation is that values are only evaluated once they are needed; it’s call by need. However, this doesn’t tell the full story.

First of all, why is lazy evaluation useful ? Let’s look at the const function:

const :: a -> b -> a
const x _ = x

As we can see, the second argument is always discarded. So what if the value of the second argument is very expensive to compute? The answer is it does not matter, since the value is not needed! This also extends to case distinction (e.g., if-then-else or pattern matching). Let’s say we have code like this:

expensive1 :: Int
expensive1 = ... -- something terribly expensive

expensive2 :: Int
expensive2 = ... -- something terribly expensive

f :: Bool -> Int
f b = if b then expensive1 else expensive2

In the evaluation of f, we only ever need to evaluate one of the two values. The other one is simply ignored!

B.1 Lazy data structures

In chapter 5, we exploit lazy evaluation in our search algorithm. We construct a graph lazily and also search it lazily (since everything in Haskell is lazy by default). This enables us to evaluate only the searched part of the graph.

A prime example of lazy data structures is infinite lists. Yes, you heard correctly:

nat :: Int
nat = [1..]

Just like this, we can construct a list with all natural numbers. Why does that work? Let’s look at an alternative implementation:

B.2 How it works

B.3 Leaking space and time

B.4 undefined and newtype