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...nkWe apply now the method seen for primitive recursion (which works for every kind of recursive definition): Define H as
val f(n1,...,nk) = h 0 n1...nk
H = fn h' => fn n => fn n1 => ... fn nk => if g(n,n1,...,nk) = 0 then n else h' (n+1) n1...nkThen we can define
[h] = Y [H]
[f] = [h]
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. 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)).
fun f(n) = second (phin (0,g))
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  [g]))
E1 = E2where 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.
x = (2*x3 - 6) / 5has solution x = 2, in fact
2 = (2*23 - 6) / 5 holds.
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) / 5Equations 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:
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.
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 MIf 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 MNow use one further abstraction step on the left, and obtain
M = (\u p. p u) MThe latter is in the format of a fixpoint equation. Then we have that a solution is
M =def= Y (\u p. p u)
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 fwhere 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 solutionThis 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) = 1and
f1(n) = undefined for n>0
f2(0) = 1So, a recursive definition of this kind (namely, with several solutions), is ambiguous, at least in principle.
f2(n) = 42 for n>0
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)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.
= 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)
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]  = ([F] ([f]))  = ([F] ([F] ([f])))  = ([F] ([F] ([F] ([f]))))  ...because
Y [F]  = ([F] (Y [F]))  = ([F] ([F] (Y [F])))  = ([F] ([F] ([F] (Y [F]))))  ...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].