You are on page 1of 16

82 9.

4 Undenability
showing that it is denable in /nat is to observe that A(m + 1, n) it-
erates n times the function A(m, ), starting with A(m, 1). As an auxiliary,
let us dene the higher-order function
it : (nat nat) nat nat nat
to be the -abstraction

(f :nat nat)

(n:nat) rec n z id | s( ) with g f g,


where id =

(x:nat) x is the identity, and f g =

(x:nat) f (g(x)) is
the composition of f and g. It is easy to check that
it(f )(n)(m) f
(n)
(m) : nat,
where the latter expression is the n-fold composition of f starting with m.
We may then dene the Ackermann function
e
a
: nat nat nat
to be the expression

(m:nat) rec mz s | s( ) with f

(n:nat) it(f )(n)(f (1)).


It is instructive to check that the following equivalences are valid:
e
a
(0)(n) s(n) (9.6)
e
a
(m + 1)(0) e
a
(m)(1) (9.7)
e
a
(m + 1)(n + 1) e
a
(m)(e
a
(s(m))(n)). (9.8)
That is, the Ackermann function is denable in /nat .
9.4 Undenability
It is impossible to dene an innite loop in /nat .
Theorem 9.4. If e : , then there exists v val such that e v : .
Proof. See Corollary 47.12.
VERSION 1.30 REVISED 03.15.2012
9.4 Undenability 83
Consequently, values of function type in /nat behave like mathe-
matical functions: if f : and e : , then f (e) evaluates to a value of
type . Moreover, if e : nat, then there exists a natural number n such that
e n : nat.
Using this, we can show, using a technique called diagonalization, that
there are functions on the natural numbers that are not denable in /nat .
We make use of a technique, called G odel-numbering, that assigns a unique
natural number to each closed expression of /nat . This allows us
to manipulate expressions as data values in /nat , and hence permits
/nat to compute with its own programs.
1
The essence of G odel-numbering is captured by the following simple
construction on abstract syntax trees. (The generalization to abstract bind-
ing trees is slightly more difcult, the main complication being to ensure
that all -equivalent expressions are assigned the same G odel number.) Re-
call that a general ast, a, has the form o(a
1
, . . . , a
k
), where o is an operator
of arity k. Fix an enumeration of the operators so that every operator has
an index i N, and let m be the index of o in this enumeration. Dene the
G odel number a of a to be the number
2
m
3
n
1
5
n
2
. . . p
n
k
k
,
where p
k
is the kth prime number (so that p
0
= 2, p
1
= 3, and so on), and
n
1
, . . . , n
k
are the G odel numbers of a
1
, . . . , a
k
, respectively. This assigns a
natural number to each ast. Conversely, given a natural number, n, we may
apply the prime factorization theorem to parse n as a unique abstract
syntax tree. (If the factorization is not of the appropriate form, which can
only be because the arity of the operator does not match the number of
factors, then n does not code any ast.)
Now, using this representation, we may dene a (mathematical) func-
tion f
univ
: N N N such that, for any e : nat nat, f
univ
(e)(m) =
n iff e(m) n : nat.
2
The determinacy of the dynamics, together with The-
orem9.4, ensure that f
univ
is a well-dened function. It is called the universal
function for /nat because it species the behavior of any expression
e of type nat nat. Using the universal function, let us dene an auxil-
iary mathematical function, called the diagonal function, d : N N, by the
equation d(m) = f
univ
(m)(m). This function is chosen so that d(e) = n iff
1
The same technique lies at the heart of the proof of G odels celebrated incompleteness
theorem. The undenability of certain functions on the natural numbers within /nat
may be seen as a form of incompleteness similar to that considered by G odel.
2
The value of f
univ
(k)(m) may be chosen arbitrarily to be zero when k is not the code of
any expression e.
REVISED 03.15.2012 VERSION 1.30
84 9.5 Notes
e(e) n : nat. (The motivation for this denition will become apparent
in a moment.)
The function d is not denable in /nat . Suppose that d were de-
ned by the expression e
d
, so that we have
e
d
(e) e(e) : nat.
Let e
D
be the expression

(x:nat) s(e
d
(x))
of type nat nat. We then have
e
D
(e
D
) s(e
d
(e
D
))
s(e
D
(e
D
)).
But the termination theoremimplies that there exists n such that e
D
(e
D
)
n, and hence we have n s(n), which is impossible.
We say that a language / is universal if it is possible to write an inter-
preter for / in / itself. It is intuitively evident that f
univ
is computable in
the sense that we can dene it in a sufciently powerful programming lan-
guage. But the preceding argument shows that /nat is not sufciently
powerful for this task. That is, /nat is not universal. By demanding
termination we sacrice expressiveness. The preceding argument shows
that this is an inescapable tradeoff. If you want universality, you have to
give up termination, and if you want termination, then you must give up
universality. There is no alternative.
9.5 Notes
/nat was introduced by G odel in his study of the consistency of arith-
metic (G odel, 1980). G odel showed how to compile proofs in arithmetic
into well-typed terms of the language /nat , and to reduce the consis-
tency problem for arithmetic to the termination of programs in /nat .
This was perhaps the rst programming language whose design was di-
rectly inuenced by the verication (of termination) of its programs.
VERSION 1.30 REVISED 03.15.2012
Chapter 10
Plotkins PCF
The language /nat , also known as Plotkins PCF, integrates functions
and natural numbers using general recursion, a means of dening self-referential
expressions. In contrast to /nat expressions in /nat might not
terminate when evaluated: its denable functions are, in general, partial
rather than total. Informally, the difference between /nat and /nat
is that the former moves the proof of termination for an expression from
the expression itself into the mind of the programmer. The type system no
longer ensures termination, which permits a wider range of functions to be
dened in the system, but at the cost of admitting innite loops when the
termination proof is either incorrect or absent.
The crucial concept embodied in /nat is the xed point characteri-
zation of recursive denitions. In ordinary mathematical practice one may
dene a function f by recursion equations such as these:
f (0) 1
f (n + 1) (n + 1) f (n).
These may be viewed as simultaneous equations in the variable, f , ranging
over functions on the natural numbers. The function we seek is a solution to
these equationsa function f : N Nsuch that the above conditions are
satised. We must, of course, show that these equations have a unique so-
lution, which is easily shown by mathematical induction on the argument
to f .
The solution to such a system of equations may be characterized as
the xed point of an associated functional (operator mapping functions to
86
functions). To see this, let us re-write these equations in another form:
f (n)

1 if n = 0
n f (n
/
) if n = n
/
+ 1.
Re-writing yet again, we seek f given by
n

1 if n = 0
n f (n
/
) if n = n
/
+ 1.
Now dene the functional F by the equation F( f ) = f
/
, where f
/
is given by
n

1 if n = 0
n f (n
/
) if n = n
/
+ 1.
Note well that the condition on f
/
is expressed in terms of the argument, f ,
to the functional F, and not in terms of f
/
itself! The function f we seek is
then a xed point of F, which is a function f : N Nsuch that f = F( f ). In
other words f is dened to the x(F), where x is an operator on functionals
yielding a xed point of F.
Why does an operator such as F have a xed point? Informally, a
xed point may be obtained as the limit of a series of approximations of
the desired solution obtained by iterating the functional F. This is where
partial functions come into the picture. Let us say that a partial func-
tion, on the natural numbers, is an approximation to a total function, f ,
if (m) = n implies that f (m) = n. Let : N N be the totally unde-
ned partial function(n) is undened for every n N. Intuitively, this
is the worst approximation to the desired solution, f , of the recursion
equations given above. Given any approximation, , of f , we may im-
prove it by considering
/
= F(). Intuitively,
/
is dened on 0 and on
m + 1 for every m 0 on which is dened. Continuing in this manner,

//
= F(
/
) = F(F()) is an improvement on
/
, and hence a further im-
provement on . If we start with as the initial approximation to f , then
pass to the limit
lim
i0
F
(i)
(),
we will obtain the least approximation to f that is dened for every m N,
and hence is the function f itself. Turning this around, if the limit exists, it
must be the solution we seek.
This xed point characterization of recursion equations is taken as a
primitive concept in /nat we may obtain the least xed point of any
VERSION 1.30 REVISED 03.15.2012
10.1 Statics 87
functional denable in the language. Using this we may solve any set of
recursion equations we like, with the proviso that there is no guarantee
that the solution is a total function. Rather, it is guaranteed to be a partial
function that may be undened on some, all, or no inputs. This is the price
we pay for expressive powerwe may solve all systems of equations, but
the solution may not be as well-behaved as we might like. It is our task as
programmers to ensure that the functions dened by recursion are total
all of our loops terminate.
10.1 Statics
The abstract binding syntax of /nat is given by the following gram-
mar:
Typ ::= nat nat naturals
parr(
1
;
2
)
1

2
partial function
Exp e ::= x x variable
z z zero
s(e) s(e) successor
ifz(e; e
0
; x.e
1
) ifz e z e
0
| s(x) e
1
zero test
lam[](x.e)

(x:) e abstraction
ap(e
1
; e
2
) e
1
(e
2
) application
fix[](x.e) fix x: is e recursion
The expression fix[](x.e) is called general recursion; it is discussed in
more detail below. The expression ifz(e; e
0
; x.e
1
) branches according to
whether e evaluates to z or not, binding the predecessor to x in the case
that it is not.
The statics of /nat is inductively dened by the following rules:
, x : x :
(10.1a)
z : nat
(10.1b)
e : nat
s(e) : nat
(10.1c)
e : nat e
0
: , x : nat e
1
:
ifz(e; e
0
; x.e
1
) :
(10.1d)
REVISED 03.15.2012 VERSION 1.30
88 10.2 Dynamics
, x :
1
e :
2
lam[
1
](x.e) : parr(
1
;
2
)
(10.1e)
e
1
: parr(
2
; ) e
2
:
2
ap(e
1
; e
2
) :
(10.1f)
, x : e :
fix[](x.e) :
(10.1g)
Rule (10.1g) reects the self-referential nature of general recursion. To show
that fix[](x.e) has type , we assume that it is the case by assigning that
type to the variable, x, which stands for the recursive expression itself, and
checking that the body, e, has type under this very assumption.
The structural rules, including in particular substitution, are admissible
for the static semantics.
Lemma 10.1. If , x : e
/
:
/
, e : , then [e/x]e
/
:
/
.
10.2 Dynamics
The dynamic semantics of /nat is dened by the judgements e val,
specifying the closed values, and e e
/
, specifying the steps of evaluation.
The judgement e val is dened by the following rules:
z val
(10.2a)
[e val]
s(e) val
(10.2b)
lam[](x.e) val
(10.2c)
The bracketed premise on Rule (10.2b) is to be included for the eager inter-
pretation of the sucessor operation, and omitted for the lazy interpretation.
(See Chapter 37 for a further discussion of laziness.)
The transition judgement e e
/
is dened by the following rules:

e e
/
s(e) s(e
/
)

(10.3a)
e e
/
ifz(e; e
0
; x.e
1
) ifz(e
/
; e
0
; x.e
1
)
(10.3b)
ifz(z; e
0
; x.e
1
) e
0
(10.3c)
VERSION 1.30 REVISED 03.15.2012
10.2 Dynamics 89
s(e) val
ifz(s(e); e
0
; x.e
1
) [e/x]e
1
(10.3d)
e
1
e
/
1
ap(e
1
; e
2
) ap(e
/
1
; e
2
)
(10.3e)

e
1
val e
2
e
/
2
ap(e
1
; e
2
) ap(e
1
; e
/
2
)

(10.3f)
[e val]
ap(lam[](x.e); e
2
) [e
2
/x]e
(10.3g)
fix[](x.e) [fix[](x.e)/x]e
(10.3h)
The bracketed Rule (10.3a) is to be included for an eager interpretation of
the successor, and omitted otherwise. Bracketed Rule (10.3f) and the brack-
eted premise on Rule (10.3g) are to be included for a call-by-value interpre-
tation, and omitted for a call-by-name interpretation, of function applica-
tion. Rule (10.3h) implements self-reference by substituting the recursive
expression itself for the variable x in its body; this is called unwinding the
recursion.
Theorem 10.2 (Safety). 1. If e : and e e
/
, then e
/
: .
2. If e : , then either e val or there exists e
/
such that e e
/
.
Proof. The proof of preservation is by induction on the derivation of the
transition judgement. Consider Rule (10.3h). Suppose that fix[](x.e) :
. By inversion and substitution we have [fix[](x.e)/x]e : , as re-
quired. The proof of progress proceeds by induction on the derivation of
the typing judgement. For example, for Rule (10.1g) the result follows im-
mediately since we may make progress by unwinding the recursion.
It is easy to check directly that if e val, then e is irreducible in that there
is no e
/
such that e e
/
. The safety theorem implies the converse, namely
that an irreducible expression is a value, provided that it is closed and well-
typed.
Denitional equality for the call-by-name variant of /nat , written
e
1
e
2
: , is dened to be the strongest congruence containing the
following axioms:
ifz(z; e
0
; x.e
1
) e
0
:
(10.4a)
REVISED 03.15.2012 VERSION 1.30
90 10.3 Denability
ifz(s(e); e
0
; x.e
1
) [e/x]e
1
:
(10.4b)
fix[](x.e) [fix[](x.e)/x]e :
(10.4c)
ap(lam[
1
](x.e
2
); e
1
) [e
1
/x]e
2
:
(10.4d)
These rules are sufcient to calculate the value of any closed expression of
type nat: if e : nat, then e n : nat iff e

n.
10.3 Denability
General recursion is a very exible programming technique that permits a
wide variety of functions to be dened within /nat . The drawback
is that, in contrast to primitive recursion, the termination of a recursively
dened function is not intrinsic to the program itself, but rather must be
proved extrinsically by the programmer. The benet is a much greater free-
dom in writing programs.
Let us write fun x(y:
1
):
2
is e for a recursive function within whose
body, e :
2
, are bound two variables, y :
1
standing for the argument and
x :
1

2
standing for the function itself. The dynamic semantics of this
construct is given by the axiom
(fun x(y:
1
):
2
is e)(e
1
) [fun x(y:
1
):
2
is e, e
1
/x, y]e
.
That is, to apply a recursive function, we substitute the recursive function
itself for x and the argument for y in its body.
Recursive functions may be dened in /nat using a combination
of recursion and functions, writing
fix x:
1

2
is

(y:
1
) e
for fun x(y:
1
):
2
is e. It is a good exercise to check that the static and
dynamic semantics of recursive functions are derivable fromthis denition.
The primitive recursion construct of /nat is dened in /nat
using recursive functions by taking the expression
rec e z e
0
| s(x) with y e
1

VERSION 1.30 REVISED 03.15.2012


10.3 Denability 91
to stand for the application, e
/
(e), where e
/
is the general recursive function
fun f (u:nat): is ifz u z e
0
| s(x) [ f (x)/y]e
1
.
The static and dynamic semantics of primitive recursion are derivable in
/nat using this expansion.
In general, functions denable in /nat are partial in that they may
be undened for some arguments. A partial (mathematical) function, :
N N, is denable in /nat iff there is an expression e

: nat nat
such that (m) = n iff e

(m) n : nat. So, for example, if is the totally


undened function, then e

is any function that loops without returning


whenever it is called.
It is informative to classify those partial functions that are denable
in /nat . These are the so-called partial recursive functions, which are
dened to be the primitive recursive functions augmented by the minimiza-
tion operation: given (m, n), dene (n) to be the least m 0 such that
(1) for m
/
< m, (m
/
, n) is dened and non-zero, and (2) (m, n) = 0. If no
such m exists, then (n) is undened.
Theorem10.3. A partial function on the natural numbers is denable in /nat
iff it is partial recursive.
Proof sketch. Minimization is readily denable in /nat , so it is at least
as powerful as the set of partial recursive functions. Conversely, we may,
with considerable tedium, dene an evaluator for expressions of /nat
as a partial recursive function, using G odel-numbering to represent expres-
sions as numbers. Consequently, /nat does not exceed the power of
the set of partial recursive functions.
Churchs Law states that the partial recursive functions coincide with
the set of effectively computable functions on the natural numbersthose
that can be carried out by a program written in any programming language
currently available or that will ever be available.
1
Therefore /nat is
as powerful as any other programming language with respect to the set of
denable functions on the natural numbers.
The universal function,
univ
, for /nat is the partial function on
the natural numbers dened by

univ
(e)(m) = n iff e(m) n : nat.
1
See Chapter 17 for further discussion of Churchs Law.
REVISED 03.15.2012 VERSION 1.30
92 10.4 Notes
In contrast to /nat , the universal function
univ
for /nat is par-
tial (may be undened for some inputs). It is, in essence, an interpreter
that, given the code e of a closed expression of type nat nat, simulates
the dynamic semantics to calculate the result, if any, of applying it to the m,
obtaining n. Since this process may fail to terminate, the universal function
is not dened for all inputs.
By Churchs Law the universal function is denable in /nat . In
contrast, we proved in Chapter 9 that the analogous function is not den-
able in /nat using the technique of diagonalization. It is instructive
to examine why that argument does not apply in the present setting. As in
Section 9.4, we may derive the equivalence
e
D
(e
D
) s(e
D
(e
D
))
for /nat . The difference, however, is that this equation is not incon-
sistent! Rather than being contradictory, it is merely a proof that the expres-
sion e
D
(e
D
) does not terminate when evaluated, for if it did, the result
would be a number equal to its own successor, which is impossible.
10.4 Notes
The language /nat is derived from Plotkin (1977). Plotkin introduced
PCF to study the relationship between its operational and denotational se-
mantics, but many authors have used PCF as the subject of study for many
issues in the design and semantics of languages. In this respect PCF may
be thought of as the E. coli of programming languages.
VERSION 1.30 REVISED 03.15.2012
Part IV
Finite Data Types
Chapter 11
Product Types
The binary product of two types consists of ordered pairs of values, one from
each type in the order specied. The associated eliminatory forms are pro-
jections, which select the rst and second component of a pair. The nullary
product, or unit, type consists solely of the unique null tuple of no val-
ues, and has no associated eliminatory form. The product type admits both
a lazy and an eager dynamics. According to the lazy dynamics, a pair is
a value without regard to whether its components are values; they are not
evaluated until (if ever) they are accessed and used in another computation.
According to the eager dynamics, a pair is a value only if its components
are values; they are evaluated when the pair is created.
More generally, we may consider the nite product,
i

iI
, indexed by a
nite set of indices, I. The elements of the nite product type are I-indexed
tuples whose ith component is an element of the type
i
, for each i I.
The components are accessed by I-indexed projection operations, general-
izing the binary case. Special cases of the nite product include n-tuples,
indexed by sets of the form I = 0, . . . , n 1 , and labeled tuples, or records,
indexed by nite sets of symbols. Similarly to binary products, nite prod-
ucts admit both an eager and a lazy interpretation.
96 11.1 Nullary and Binary Products
11.1 Nullary and Binary Products
The abstract syntax of products is given by the following grammar:
Typ ::= unit unit nullary product
prod(
1
;
2
)
1

2
binary product
Exp e ::= triv null tuple
pair(e
1
; e
2
) e
1
, e
2
ordered pair
pr[l](e) e l left projection
pr[r](e) e r right projection
There is no elimination formfor the unit type, there being nothing to extract
from the null tuple.
The statics of product types is given by the following rules.
: unit
(11.1a)
e
1
:
1
e
2
:
2
e
1
, e
2
:
1

2
(11.1b)
e :
1

2
e l :
1
(11.1c)
e :
1

2
e r :
2
(11.1d)
The dynamics of product types is specied by the following rules:
val
(11.2a)
[e
1
val] [e
2
val]
e
1
, e
2
val
(11.2b)

e
1
e
/
1
e
1
, e
2
e
/
1
, e
2

(11.2c)

e
1
val e
2
e
/
2
e
1
, e
2
e
1
, e
/
2

(11.2d)
e e
/
e l e
/
l
(11.2e)
e e
/
e r e
/
r
(11.2f)
VERSION 1.30 REVISED 03.15.2012
11.2 Finite Products 97
[e
1
val] [e
2
val]
e
1
, e
2
l e
1
(11.2g)
[e
1
val] [e
2
val]
e
1
, e
2
r e
2
(11.2h)
The bracketed rules and premises are to be omitted for a lazy dynamics,
and included for an eager dynamics of pairing.
The safety theorem applies to both the eager and the lazy dynamics,
with the proof proceeding along similar lines in each case.
Theorem 11.1 (Safety). 1. If e : and e e
/
, then e
/
: .
2. If e : then either e val or there exists e
/
such that e e
/
.
Proof. Preservation is proved by induction on transition dened by Rules (11.2).
Progress is proved by induction on typing dened by Rules (11.1).
11.2 Finite Products
The syntax of nite product types is given by the following grammar:
Typ ::= prod(i
i

iI
)
i

iI
product
Exp e ::= tpl(i e
i

iI
) e
i

iI
tuple
pr[i](e) e i projection
The variable I stands for a nite index set over which products are formed.
The type prod(i
i

iI
), or
iI

i
for short, is the type of I-tuples of
expressions e
i
of type
i
, one for each i I. An I-tuple has the form
tpl(i e
i

iI
), or e
i

iI
for short, and for each i I the ith projection
from an I-tuple, e, is written pr[i](e), or e i for short.
When I = i
1
, . . . , i
n
, the I-tuple type may be written in the form
i
1

1
, . . . , i
n

in which we make explicit the association of a type to each index i I.


Similarly, we may write
i
1
e
1
, . . . , i
n
e
n

for the I-tuple whose ith component is e


i
.
Finite products generalize empty and binary products by choosing I to
be empty or the two-element set l, r , respectively. In practice I is often
REVISED 03.15.2012 VERSION 1.30

You might also like