Fall 2001, CSE 520: Lecture 4


Encoding of primitive recursion (cont'ed)

The fixpoint operator

We need a lambda term which is able to compute the fixpoint of a function, i.e. a term Y such that for every M it satisfies:
Y M = M (Y M)
One possible definition of such Y is
Y = \x. (\y. x(y y)) (\y. x(y y))
In fact, Y M = (\y. M(y y)) (\y. M(y y)) = M((\y. M(y y)) (\y. M(y y))) = M (Y M).

We can therefore define

f = Y [F]
It remains to define [F]. To this purpose, we need to define the booleans and the if-then-else operator, the test is_zero, and the predecessor.

Booleans and the if-then-else operator

Let us encode the booleans as follows:
[true] = \x y. x
[false] = \x y. y
Note that we have:
[true] M N = M
[false] M N = N
Therefore it is sufficient to define
[if_then_else] = \x y z . x y z
In fact we will have: [if_then_else] C M N = M if C = [true], and [if_then_else] C M N = N if C = [false].

Test is_zero

We can define
[is_zero] = \x. x ([true][false])[true]
In fact, [n] M N = MnN, hence [is_zero][n] = [n]([true][false])[true] = ([true][false])n[true] and the latter is equal (lambda-convertible) to [true] if n=0, and to [false] otherwise.

Predecessor

One way to define the predecessor function is by using the pairing and the projection operators, which can be defined as follows:
Pair = \x y z. z x y
First = \p. p [true]
Second = \p. p [false]
Note that this definition is a correct encoding, since we have First (Pair M N) = M and Second (Pair M N) = N. Now define the encoding of the predecessor function as follows:
Aux = \x. Pair ([S] (First x)) (First x)
Predecessor = \z. Second (z Aux (Pair [0] [0]))
Where [S] = \z x y. x (z x y) is the usual encoding of the successor function. To see how the definition works, remember that [n] M N = Mn N.

Note that the reason why we need pairing is that the Aux function needs returning a pair of values. The pair is a particular case of the concept of record in Pascal and of structure in C/C++.

An alternative definition of the predecessor function, which does not make use of pairs, is the following:

Predecessor' = \z x y. z S2 Z2 I
where
S2 = \z w. w (z x)
Z2 = \w. y
I = \u. u
We leave to the interested reader to show that also Predecessor' is a correct encoding of the predecessor function.

Note: both Predecessor and Predecessor', when applied to [0], give result [0].

Encoding of minimalization

Given the definition of f as
f(n1,...,nk) = mu n. (g(n,n1,...,nk) = 0)
we can rewrite it in ML as follows:
val rec h = fn n => fn n1 => ... fn nk => if g(n,n1,...,nk) = 0 then n else h (n+1) n1...nk
val f(n1,...,nk) = h 0 n1...nk
We apply now the method seen for primitive recursion (which works for every kind of recursive definition): Define H as
H = fn h' => fn n => fn n1 => ... fn nk => if g(n,n1,...,nk) = 0 then n else h' (n+1) n1...nk
Then we can define
[h] = Y [H]
[f] = [h][0]

Note: In the classical proof of the Klenee's theorem, the encoding of primitive recursion does not use the fixpoint operator. The fixpoint operator in fact is necessary for expressing minimalization (and general recursion), but not for primitive recursion. The classic encoding of primitive recursion is done by using "definite iteration" (i.e. iteration repeated a number of times known a-priori) and pairs to store the partial result of the computation. We give here the translation in ML and we leave the translation from ML to the Lambda Calculus as an exercise.

Let f be defined by primitive recursion as:

f(0) = g   
f(n+1) = h(n,f(n))
then f can be defined in pseudo-ML by the following declarations:
fun phi(m,n) = (m+1,h(m,n))
fun f(n) = second (phin (0,g))
Where second is the projection on the second element of a pair, i.e. second (a,b) = b. To see that the above is a correct definition, note that phi(m,f(m)) = (m+1,f(m+1)), hence phin (0,g) = (n,f(n)).

In order to translate from ML to the Lambda Calculus, we need to encode pairs and the projection operators like we did for the predecessor function. As for definite iteration, needed for representing phin, remember that in the Lambda Calculus we have MnN = [n] M N. Hence we can define

[f] = \z. Second (z [phi] (Pair [0] [g]))