For all n1, n2, ... nk, if f(n1, n2, ..., nk) is defined, then [f] [n1] [n2] ... [nk] = [f(n1, n2, ..., nk)]We don't say anything, however, of what happens if f(n1, n2, ... nk) is undefined. In general, it is not guarranteed that the encoding is undefined as well: there may exist n such that [f] [n1] [n2] ... [nk] = [n]. We will see later why this is possible.
It is natural to ask ourselves whether such encoding is good enough. It would be better, of course, to have an encoding that, in all cases in which the original function is undefined, gives as result some particular lambda term which we take as representation of "undefined". However, this is not possible: One of the basic results of the Theory of Computability says that it is not possible to give (in any system) an encoding of all computable functions as total functions.
So, there are only two alternatives: either we don't care of what our encoding gives in case the original function is undefined, or we enforce our encoding to be "undefined" as well, in the sense that we ensure that it will not lambda-convert to (the representation of) any number.
So far, we have followed the first approach. The second one, however, may be preferable: One can argue that it is better to have "no answer" rather than "a wrong answer".
In order to encode functions faithfully also in the cases of undefined result, let us first understand what are the causes of the mismatch in our previous encoding. There is essentially only one cause, and it is related to the dicotomy call-by-value / call-by-name in the definition of functional composition.
f(x) = 0 for all xWhat is the result of the call f(g(1))? It depends, of course, on the way the parameter is evaluated. We have two choices:
g(x) = undefined for all x
In the lambda calculus, however, the encoding of (f o g) (for the f and g defined above) is:
[f o g] =def= \x. [f] ([g] x) = \x. (\y. [0]) ([g] x)hence we have, for instance,
[f o g][1] = (\x. (\y. [0]) ([g] x)) [1] = (\y. [0]) ([g] [1])) = [0]Note that in the term (\y. [0]) ([g] [1])) there are two beta-conversions that we can apply: one is the top level one, which gives [0] as result, and which corresponds to call-by-name. The other is the internal one, namely the application of [g] to [1], which corresponds to call-by-value. If we keep repeating the internal one only, we may never terminate. Anyway, from the point of view of the equality theory, what counts is that at least one strategy brings to a result.
[f o g] =def= \x. (([g] x) [true] I I) ([f] ([g] x))where I = \x.x
It is easy to show that, if [g] [n] = [k], then [f o g] [n] = [f] [k]. In fact (\x. (([g] x) [true] I I) ([f] ([g] x))) [n] = (([g] [n]) [true] I I) ([f] ([g] [n])) = ([k][true] I I) ([f] [k]) = ([true]k I I) ([f] [k]) = I ([f] [k]) = [f] [k].
On the other hand, it is possible to show (even if we won't see the proof here) that, if [g] [n] is "undefined" (in the sense that it does not have a normal form, a concept that we will see later) then [f o g] [n] does not have a normal form either, which means, in particular, that there exists no m such that [f o g] [n] = [m].
The reason, intuitively, is that the term (([g] [n]) [true] I I) ([f] ([g] [n])) can be reduced to a normal form only if we eliminate the top-level application. But this is possible only if we reduce [g] [n] to a normal form. In other words, we are simulating the mechanism of call-by-value by enforcing the evaluation of [g] [n] in order to achieve a normal form for the whole expression.
With the new encoding of functional composition, and the encodings of primitive recursion and mnimalizion as before, we obtain the following stronger property for any recursive function f:
For all n1, n2, ... nk
- if f(n1, n2, ..., nk) is defined, then [f] [n1] [n2] ... [nk] = [f(n1, n2, ..., nk)]
- if f(n1, n2, ..., nk) is not defined, then [f] [n1] [n2] ... [nk] does not have a normal form. Which means, in particular, that there exist no n such that [f] [n1] [n2] ... [nk] = [n]