Suppose we want to evaluate
(rec f => fn x => if (iszero x) then x else f(pred x)) 1in environment ev0 = [].
To evaluate a function application, we first evaluate the function in the environment ev0:
(rec f => fn x => if (iszero x) then x else f(pred x), ev0) || \/ (fn x => if (iszero x) then x else f(pred x), ev1) || \/ closure(x, if (iszero x) then x else f(pred x), ev1)where ev1 is
[(f,THUNK(rec f => fn x => if (iszero x) then x else f(pred x), ev0))]That is, ev1 records the meaning of f as a thunk. The thunk makes the recursive expression and its environment into a value that can be evaluated later on. The key here is that we do NOT want to fully expand recursive functions by repeatedly replacing all occurrences of the name by the definition as it would be expanded forever. Instead we want to save the definition so that it can be expanded whereever necessary.
Now applying the rules for function application, to evaluate a closure applied to an argument, we need take apart the closure to get the body of the function, get the environment it was defined in, and then update the environment to store the value of the actual parameter as the meaning of the formal parameter. Thus we must evaluate
(if (iszero x) then x else f(pred x), ev2)where ev2 is ev1+[(x,1)].
Evaluating (iszero x, ev2) gives false because ev2(x) is 0. Therefore evaluating the if statement leads us to evaluate
(f(pred x), ev2)
To evaluate this function application, we must first evaluate f in ev2, but ev2(f) = THUNK(rec f => fn x => if (iszero x) then x else f(pred x), ev0). The rule for evaluating identifiers states that if the identifier evaluates to a THUNK, then evaluate the expression in the thunk in its environment. Thus we must evaluate
(rec f => fn x => if (iszero x) then x else f(pred x))in environment ev0. To do this, we go through the same steps as above and the evaluation of (f(pred x), ev2) reduces to evaluating
(if (iszero x) then x else f(pred x), ev3)where ev3 is ev1+[(x,0)].
At this point, it should be straightforward to see that the entire term evaluates to 0 because iszero x evaluates to true in ev3.