evaluating

Evaluation stops when a *normal form*, or *value* is reached:

- A constant belonging to a built-in type; or
- A constructor applied to the correct number of arguments (in normal form); or
- A function applied to no arguments (i.e.
`fun x -> e`

)

Call-by-value is also called *applicative order* or *eager evaluation*, and is the more common eval rule. (used in Python, Java, C/C++, OCaml,…)

Call-by-name is also called *lazy* or *normal-order evaluation*.

The rules can lead to different behavior, e.g. …

Does call-by-name always use fewer evaluations?

Call-by-name will evaluate `(fib 40)`

twice.

We can avoid this using expression sharing, where expressions are *graphs* rather than *trees*.

Call-by-name with sharing is also called *call-by-need* or *lazy evaluation*.

`lazyCaml`

Imagine programming in `lazyCaml`

:

```
type 'a tree = Empty | Leaf of 'a | Node of ('a tree) * ('a tree)
let rec dfs t = match t with
| Empty -> []
| Leaf x -> [x]
| Node (lt,rt) -> (dfs lt) @ (dfs rt)
```

Suppose we want to decide if two trees result in the same depth-first search:

```
let rec listeq l1 l2 = match (l1,l2) with
| ([],[]) -> true
| ((h1::t1), (h2::t2)) -> h1=h2 && (listeq t1 t2)
| _ -> false
let eq_dfs t1 t2 = listeq (dfs t1) (dfs t2)
```

What happens when we evaluate:

`eq_dfs Node(Node(Leaf 3, Leaf 7), Leaf 11) Node(Leaf 7, Node(Leaf 3, Leaf 11))`

`list_eq (dfs Node(Node(Leaf 3, Leaf 7), Leaf 11)) (dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))`

`list_eq ((dfs Node(Leaf 3, Leaf 7)) @ (dfs Leaf 11)) (dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))`

`list_eq ((dfs Leaf 3) @ (dfs Leaf 7) @ (dfs Leaf 11)) (dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))`

`list_eq 3::((dfs Leaf 7) @ (dfs Leaf 11)) (dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))`

`list_eq 3::((dfs Leaf 7) @ (dfs Leaf 11)) ((dfs Leaf 7) @ (dfs Node(Leaf 3, Leaf 11)))`

`list_eq 3::((dfs Leaf 7) @ (dfs Leaf 11)) 7::(dfs Node(Leaf 3, Leaf 11))`

`(3=7) && (list_eq ((dfs Leaf 7) @ (dfs Leaf 11)) (dfs Node(Leaf 3, Leaf 11)))`

`false`

```
eq_dfs Node(Node(Leaf 7, Node(Leaf 3, Leaf 11)),Leaf 2)
Node(Leaf 7, Node(Leaf 3, Leaf 11))
```

```
≡ list_eq (dfs Node(Node(Leaf 7, Node(Leaf 3, Leaf 11)),Leaf 2))
(dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))
≡ list_eq ((dfs Node(Leaf 7, Node(Leaf 3, Leaf 11))) @ (dfs Leaf 2))
(dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))
≡ list_eq ((dfs Leaf 7) @ (dfs Node(Leaf 3, Leaf 11)) @ (dfs Leaf 2))
(dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))
≡ list_eq 7::((dfs Node(Leaf 3, Leaf 11)) @ (dfs Leaf 2))
(dfs Node(Leaf 7, Node(Leaf 3, Leaf 11)))
≡ list_eq 7::((dfs Node(Leaf 3, Leaf 11)) @ (dfs Leaf 2))
((dfs Leaf 7) @ (dfs Node(Leaf 3, Leaf 11))
≡ list_eq 7::((dfs Node(Leaf 3, Leaf 11)) @ (dfs Leaf 2))
7::(dfs Node(Leaf 3, Leaf 11))
≡ list_eq ((dfs Node(Leaf 3, Leaf 11)) @ (dfs Leaf 2)) (dfs Node(Leaf 3, Leaf 11))
≡ list_eq ((dfs Leaf 3) @ (dfs Leaf 11)) @ (dfs Leaf 2)) (dfs Node(Leaf 3, Leaf 11))
≡ list_eq 3::((dfs Leaf 11) @ (dfs Leaf 2)) (dfs Node(Leaf 3, Leaf 11))
≡ list_eq 3::((dfs Leaf 11) @ (dfs Leaf 2)) ((dfs Leaf 3) @ (dfs Leaf 11))
≡ list_eq 3::((dfs Leaf 11) @ (dfs Leaf 2)) 3::(dfs Leaf 11)
≡ list_eq ((dfs Leaf 11) @ (dfs Leaf 2)) (dfs Leaf 11)
≡ list_eq 11::(dfs Leaf 2) (dfs Leaf 11)
≡ list_eq 11::(dfs Leaf 2) 11::[]
≡ list_eq (dfs Leaf 2) []
≡ list_eq 2::[] []
```

(we could write an eager OCaml function to compare trees this way…)

Also with lazy evaluation:

```
let rec nats n = n :: (nats (n+1))
let rec take n lst = match (n,lst) with
| (0,_) | (_,[]) -> []
| (_,(h::t)) -> h::(take (n-1) t)
```

Then `(take 2 (nats 0))`

is ok, even though `(nats 0)`

doesn’t terminate:

```
(take 2 (nats 0))
(take 2 (0 :: (nats 1)))
0::(take 1 (nats 1))
0::(take 1 (1::(nats 2)))
0::1::(take 0 (nats 2))
0::1::[]
```

Other infinite objects:

```
let rec squares n = (n*n) :: (squares (n+1))
let rec sum = function
| [] -> 0
| x::xs -> x + sum xs
```

evaluating `(sum (take 3 (squares 3)))`

:

```
sum (take 3 (9::(squares 4)))
sum 9::(take 2 (squares 4))
9+(sum (take 2 (squares 4)))
9+(sum (take 2 (16::(squares 5))))
9+(sum 16::(take 1 (squares 5)))
9+16+(sum (take 1 (squares 5)))
25+(sum (take 1 (squares 5)))
25+(sum (take 1 25::(squares 6)))
25+(sum 25::(take 0 (squares 6)))...
```

Even with lazy evaluation, some expressions will fail to terminate, e.g.

```
List.exists ((>) 0) (nats 0)
List.exists ((>) 0) 0::(nats 1)
(0 > 0) || (List.exists ((>) 0) (nats 1))
false || (List.exists ((>) 0) (nats 1))
List.exists ((>) 0) (nats 1)
List.exists ((>) 0) 1::(nats 2)
(0 > 1) || (List.exists ((>) 0) (nats 2))
...
```

And

```
let rec whee x = whee (x+1)
List.exists (whee) [1]
≡ (whee 1) || (List.exists whee [])
≡ (whee 2) || (List.exists whee [])
≡ (whee 3) || (List.exists whee [])
...
```

`cs2041.org`