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

A partial function f : N^{k} -> N
is lambda-definable if there exists a lambda term [f]
such that, whenever f(n_{1},...,n_{k}) is defined,
we have

[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] = \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-1,f(n-1))or equivalently (remember that the syntax for \n. M[n] in ML is fn n => M[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

Pair = \x y z. z x yNote 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:

First = \p. p [true]

Second = \p. p [false]

Aux = \x. Pair ([S] (First x)) (First x)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 = M

Predecessor = \z. Second (z Aux (Pair [0] [0]))

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 Iwhere

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

Z2 = \w. y

I = \u. u

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