Fall 2001, CSE 520: Lecture 5

Examples of encoding of functions into lambda terms

Recursive definitions and fixpoints

In this section we review the concepts of recursive definition and fixpoint operator, and try to give some further explanation about them. Let us start with some basic definition.

Equations and solutions of equations

Given an equality theory, an equation on x is a formula of the form
E1 = E2
where E1 are E2 are expressions containing some (zero, one, or several) occurrences of x.

A solution for the above equation is any value v such that

E1[v/x] = E2[v/x]   holds (i.e. this equality is a consequence of the theory)
where [v/x] represents the substitution of v for x. Of course, an equation can have zero, one, or several solutions.


In the theory of rational numbers, the equation
x = (2*x3 - 6) / 5
has solution x = 2, in fact
2 = (2*23 - 6) / 5 holds.

Recursive definitions

The equation of the example above is in a particular format: it has the form

x = f(x)
where f is the function defined as
f(y) =def= (2 y3 - 6) / 5
Equations in this format are called ``fixpoint equations'' and also ``recursive definitions''. The latter terminology is a bit misleading, because it leads to think that such equation is a definition of x. The idea indeed is that x is defined, by such equation, as the solution of the equation. However:
  1. The equation may not have any solution. Example: x = x+1 has no solution in the natural numbers.
  2. The equation may have more than one solution. Example: x = x2 has two solutions: x = 0 and x = 1.
Only in the ``lucky case'' that x = f(x) has one and only one solution, then we can consider such equation a real definition of x.
Note: The solutions of x = f(x) are called ``fixpoints of f''.

For certain theories, the solution of fixpoint equations can be obtained in a uniform way, by applying an operator to the function f of the equation. Such operator is called fixpoint operator.

The fixpoint operators in lambda calculus

The theory of lambda calculus has fixpoint operators. One fixpoint operator is the lambda term Y defined in previous lectures. In fact, as previously proved, we have
Y F = F (Y F)
for every lambda term F. This means that every fixpoint equation
X = F (X)
has a solution X =def= Y F.

Note that Y is not the only fixpoin operator in the lambda calculus. We have, actually, infinitely many such operators. The operator Y is due to Curry, and was called by him "paradoxical combinator". Another fixpoint operator, due to Turing, is the term (\x y. y (x x y))(\x y. y (x x y)).

Example Suppose that we want to find a term M such that, for every P, we have:

M P = P M
If we are able to reduce the above equation to a fixpoint equation, then we can use the fixpoint operator to solve this problem.

Observe that the above equation is equivalent to

M = \p. p M
Now use one further abstraction step on the left, and obtain
M = (\u p. p u) M
The latter is in the format of a fixpoint equation. Then we have that a solution is
M =def= Y (\u p. p u)

Recursive definitions of functions

Consider a recursive definition of a (partial) function f, like for instance
f(n)   =def=   if n = 0 then ... else ... f(n-1) ...
or equivalently
f   =def=   \n. if n = 0 then ... else ... f(n-1) ...
what we mean by such a definition is that we want to define f as the solution of a fixpoint equation on f of the form
f = F f
where F is the function defined as
F   =def=   (\u. \n. if n = 0 then ... else ... u(n-1) ...)
The recursive definitions (fixpoint equations) of functions enjoy an important property, namely
In the domain of functions, a fixpoint equation f = F f admits always at least one solution
This is because we are considering partial functions, namely functions which can be undefined on any argument.

There may be, hoverer, more than one solution. For example, consider the following recursive definition:

f(n) = if n = 0 then 1 else f(n+1)
There are infinitely many solutions for this equations. All of them must return 1 in correspondence of 0, but, on the other arguments, there is complete freedom. For instance, the following functions are solutions of the above equation:
f1(0) = 1
f1(n) = undefined    for n>0
f2(0) = 1
f2(n) = 42   for n>0
So, a recursive definition of this kind (namely, with several solutions), is ambiguous, at least in principle.

In practive however, when we write in a a recursive definition of this kind in a program, there is no ambiguity: the operational semantics of the language ensures that the intended solution is uniquely defined. Usually, such intended solution is the most partial function (the function wich returns ``undefined'' most often). In the example above, the intended solution would be f1. The reason why we get the most undefined solution is that the operational semantics of recursive definitions is (usually) based on unfolding. For example, a call of f(5), where f is defined as above, gives rise to the following sequence of unfoldings:

f(5) = if 5 = 0 then 1 else f(6)
     = if 5 = 0 then 1 else if 6 = 0 then 1 else f(7)
     = if 5 = 0 then 1 else if 6 = 0 then 1 else if 7 = 0 then 1 else f(8)
     = ...
So, if the test for termination is on 0, recursive calls on non-decreasing arguments will give rise to non-terminating loops, and therefore be undefined.

More in general, a call f(k) where f = F f will give rise to a sequence of the form

f(5) = (F f) 5 = (F (F f)) 5 = (F (F (F f))) 5 = ...
Note that the fixpoint operator of the lambda calculus also fives this kind of behavior: if we define [f] = Y [F], we have:
[f] [5] = ([F] ([f])) [5] = ([F] ([F] ([f]))) [5] = ([F] ([F] ([F] ([f])))) [5] ...
Y [F] [5] = ([F] (Y [F])) [5] = ([F] ([F] (Y [F]))) [5] = ([F] ([F] ([F] (Y [F])))) [5] ...
Therefore the definition of [f] as Y [F] corresponds to take as solution of   f = F f   the most partial one (Provided of course that the functions used in the definition. of F are represented faithfully with respect to partiality.) This means that, if we call f' such most partial solution, we have that: if f'(n) is defined then [f] [n] = [f'(n)], and if f'(n) is not defined then there exists no k such that [f] [n] = [k].

Mutually recursive functions

Mutually recursive functions can be defined in lambda calculus by using pairs. For instance, assume that we have the following definitions:
f = F f g
g = G f g
Using pairs, this system of equations can be transformed into the single equation
(f,g) = (F f g, G f g)
We need however to write it in the fixpoint format. This can be done as follows:
(f,g) = (\p. (F (First p) (Second p), G (First p) (Second p)) ) (f,g)
Or, more in general
X = (\p. (F (First p) (Second p), G (First p) (Second p)) ) X
Note that the fixpoint of (\p. (F (First p) (Second p), G (First p) (Second p)) ) will necessarily be a pair, because that's what the result of this function is, hence we don't need to impose that X is a pair.

The lambda representation of the solution of this equation is therefore

[X] =def= Y (\p. [Pair] ([F] ([First] p) ([Second] p)) ( [G] ([First] p) ([Second] p)) )

Note that we can separate the components of [X] by using [First] and [Second]. Namely, [First][X] will give [f] and [Second][X] will give [g].