Lecture 26-1
Evaluation Strategies
inc x = x + 1
square x = x * x
So square (inc 2) = (2 + 1) * (2 + 1) = 9
. How does Haskell evaluate this?
Strict Evaluation
In strict evaluation, we always apply the innermost function first:
square (inc 2)
square (3)
3 * 3
9
Here we first apply inc
and then apply square
.
This means that when we call a function we first evaluate its argument.
This is the method that imperative languages use to evaluate functions. Haskell does not evaluate this way
Lazy Evaluation
In lazy evaluation, we always apply the outermost functions first:
square (inc 2)
inc 2 * inc 2
3 * 3
9
First apply square
then apply inc
.
This method waits as long as possible until computing values.
In the following, nothing is computed until we ask for the value of z
.
> let x = 1 + 1
> let y = x + x
> let z = y / 2
> z
2.0
> let x = 1 + undefined
> let y = x + x
> let z = y / 2
> z
*** Exception: Prelude.undefined
You can see here that the error only occurs when the binding is evaluated.
If a value is never used, it is never computed:
> let f x = 1
> f undefined
1
You can see here that the argument is not evaluated. This results in the program not crashing due to evaluating undefined
.
Imperative Languages
Imperative languages are always strict:
- So programmers know the order of their side effects.
Functional Languages
For pure functions the order of evaluation is irrelevant.
-
You always get the same answer.
-
No need to worry about side effects.
Some functional languages are strict by default:
- ML
- Ocaml
Others are lazy by default:
- Haskell
Lazy vs. Strict
If strict evaluation finds an answer, the lazy evaluation fill find the same answer.
Sometimes lazy evaluation can find an answer when strict evaluation cannot:
> fst (1, 1 `div` 0)
1
A strict evaluator would crash in this example.
Sometimes lazy evaluation can be more efficient than strict:
- Particularly if some values are computed but never used.
Lazy evaluation only ever computed a value when it is needed. This can lead to big efficiency savings:
- When computing the the head of a doubled list.
Summary
Strict evaluation:
- Evaluate things as soon as possible.
- Gives certainty over order of side effects.
Lazy evaluation:
- Evaluate things only when they are needed.
- Potentially eliminates unneeded computation.
Exercise
1
-
[5,10,*** Exception: divide by zero
This is due to the fact that it evaluates last so will print the first two elements. This is opposed to crashing immediately.
*** Exception: divide by zero