[n] = \x y. xwhere, for generic lambda terms M and N, M^{n}y

[f][nThe equality here is the "lambda-convertibility" (see previous lecture), i.e. the equality in the theory of Lambda Calculus. Note that [f] is curried, i.e. it takes its arguments one by one._{1}]...[n_{k}] = [f(n_{1},...,n_{k})]

- Zero: Z(n) = 0
- Successor: S(n) = n+1
- Projection:
U
^{p}_{i}(n_{1},...,n_{p}) = n_{i}

(f o (g_{1},...,g_{k})) (n_{1},...,n_{h}) = f(g_{1}(n_{1},...,n_{h}),..., g_{k}(n_{1},...,n_{h}))

f(0,n_{1},...,n_{k}) = g(n_{1},...,n_{k})

f(n+1,n_{1},...,n_{k}) = h(n, f(n,n_{1},...,n_{k}), n_{1},...,n_{k})

f(nwhere mu is the minimalization operator: mu n. P(n) returns the least natural number n such that P(n) holds._{1},...,n_{k}) = mu n. (g(n,n_{1},...,n_{k}) = 0)

Note that f could be defined by general iteration, i.e. using a while loop of the form

n := 0; while (g(n,n_{1},...,n_{k}) <> 0) do n := n+1;

**Definition** The set of *Recursive Functions* is the
smallest set which contains the initial functions and is closed w.r.t.
composition, primitive recursion, and minimalization.

If we exclude minimalization from this construction, we get the set of
*Primitive Recursive Fuctions*, which are all total.
Minimalization is the only operator which introduces non-termination, i.e.
partiality.

**Theorem** (Kleene, 1936) Every recursive function is
lambda-definable.

- Zero: [Z] = \x.[0]
- Successor: [S] = \z.\x y. x(z x y)
- Projection:
[U
^{p}_{i}] = \x_{1}...x_{p}.x_{i}

[S][n] = (\z.\x y. x(z x y))[n] = \x y. x([n] x y) = \x y. x(x^{n}y) = [n+1]

[f o (g_{1},...,g_{k})] = \x_{1}...x_{h}. [f]([g_{1}]x_{1}...x_{h}) ... ([g_{k}]x_{1}...x_{h})

f(0) = g (constant)In ML we could define this function as:

f(n+1) = h(n,f(n))

fun f(n) = if n = 0 then g else h(n,f(n))or equivalently (remember that the syntax for \n.E(n) in ML is fn n => E(n)) :

val rec f = fn n => if n = 0 then g else h(n-1,f(n-1))The meaning of this declaration is that f is a fixpoint of the following functional F:

F = fn f' => fn n => if n = 0 then g else h(n-1,f'(n-1))Namely, f satisfies the equation

f = F(f)

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.

[True] = \x y. xNote that we have:

[False] = \x y. y

[True] M N = MTherefore it is sufficient to define

[False] M N = N

[if_then_else] = \x y z . x y zIn 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].

[is_zero] = \x. x ([True][False])[True]In fact, [n] M N = M

f(nwe can rewrite it in ML as follows:_{1},...,n_{k}) = mu n. (g(n,n_{1},...,n_{k}) = 0)

val rec h = fn n => fn nWe apply now the method seen for primitive recursion (which works for every kind of recursive definition): Define H as_{1}=> ... fn n_{k}=> if g(n,n_{1},...,n_{k}) = 0 then n else h n n_{1}...n_{k}

val f(n_{1},...,n_{k}) = h 0 n_{1}...n_{k}

H = fn h' => fn n => fn nThen we can define_{1}=> ... fn n_{k}=> if g(n,n_{1},...,n_{k}) = 0 then n else h' n n_{1}...n_{k}

[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) = gthen f can be defined in pseudo-ML by the following declarations:

f(n+1) = h(n,f(n))

fun phi(m,n) = ( m+1 , h(m,n) )Where Second is the projection on the second element of a pair, i.e. (a,b) Second = b. To see that the above is a correct encoding, note that phi(m,f(m)) = (m+1,f(m+1)), hence phi

fun f(n) = (phi^{n}(0,g)) Second

In order to translate from ML to the Lambda Calculus,
we need to encode pairs and the projection operators.
(We leave this as an exercise.)
As for definite iteration, needed for representing
phi^{n}, note that in the Lambda Calculus
we have M^{n}N = [n] M N.