one day seminar professor roland backhouse...functional programming logic programming program...

69
BCS FACS ONE DAY SEMINAR Professor Roland Backhouse University of Groningen at Imperial College Room 145 Huxley on Monday 14 September 1987 1030 -1600 THE MARTIN-LOF THEORY OF TYPES A COMPUTING SCIENTIST'S PERSPECTIVE 1. Introduction - An insight into constructive proofs and their relation to programs 2. The construction of the rules with examples, lists and finite bags 3. An example of algorithm development This list of topics is provisional and may change £15 to include coffee, lunch and tea (Cheques payable to BCS FACS) Enquiries to: Jennifer Eastwood, Dept of Computing, Imperial College, 180 Queen's Gate, London SW7 2BZ 01-5895111 ext 5021 Telex 261503

Upload: others

Post on 18-Jul-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

BCS FACS

ONE DAY SEMINAR

Professor Roland Backhouse University of Groningen

at Imperial College Room 145 Huxley

on Monday 14 September 1987 1030 -1600

THE MARTIN-LOF THEORY OF TYPES A COMPUTING SCIENTIST'S PERSPECTIVE

1. Introduction - An insight into constructive proofs and their relation to programs

2. The construction of the rules with examples, lists and finite bags 3. An example of algorithm development

This list of topics is provisional and may change

£15 to include coffee, lunch and tea (Cheques payable to BCS FACS)

Enquiries to: Jennifer Eastwood, Dept of Computing, Imperial College, 180 Queen's Gate, London SW7 2BZ 01-5895111 ext 5021 Telex 261503

Page 2: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Notes on Martin-Lof's Theory of Types Roland Backhouse.

Subfaculteit Wiskunde en Informatica Rijksuniversiteit Groningen

Postbus 800 9700 AV GRONINGEN

The Netherlands

Every so often in the development of a scieL.ce a new topic emerges that captures every­one's imagination and instigates a furore of activity. A topic that has recently captured my imagination and the imagination of a small, but growing, number of computing scientists is Per Martin-Lof's theory of types [M-Lll. It has yet to capture the imagination of a large body of computing scientists, although I believe it will eventually do so, partly because of seemingly inevitable difficulties of communication between logicians and computing scien­tists. These notes are an attempt to overcome some of these difficulties by explicating the theory with a substantial number of examples. The examples I have chosen, and the order and style of presentation, will, I hope, appeal to computing scientists with an interest in programming as a mathematical activity.

By way of motivation, and in order to explain why I, personally, am impressed by the theory, I shall begin with a very brief review of some of the more important advances that have been made in the "mathematics of programming" since 1968. I have taken 1968 as the starting point since that was the year of a now-famous NATO conference on Software Engineering in Garmisch, West Germany *.It was at that conference, I believe, that the term "software crisis" was coined. More importantly, it was at that conference that the computing community became publicly aware of the vital need for a theory of programming. The four developments that I discuss are these.

Data Structuring Functional Programming Logic Programming Program Verification

The first of these, the introduction of type declarations (enumerated types, record structures etc.) into programming languages is also, historically, the first to have had a significant impact on the way we program. C. A. R. Hoare's suggestions on data structuring [Ho], which were subsequently realised in the programming language Pascal, were made with the expressed aim of tlextend(ing) the range of programming errors which logically cannot be made J7

That this objective was achieved is undoubtedly true, but the notion of strong typing - the requirement that the left and right sides of all assignments (implicit or explicit) have identical type - introduced in Pascal to achieve that objective involved a severe penalty of inflexibility. For example, it is impossible to define in Pascal an identity function - a

* 1968 was also the year that C.A.R.Hoare took up a chair at Queen's University, Belfast.

1

Page 3: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

function that takes an arbitrary value as argument and returns the same value as result. It, is, however, possible to write separate identity functions for integers;-for Booleans etc. This may not seem to be a very significant example; its significance becomes more apparent when one realises that separate, but essentially identical, procedures are needed to search a list ofl;, widgets for a widget and to search a list of thingummyjigs for a thingummyjig.

One of the benefits of some functional programming languages was to liberate us from the strait-jacket of strong-typing without compromising Hoare's stricture on extending the range of errors which logically cannot be made. Thus in the language ML, developed by Robin Milner and his colleagues as part of the Edinburgh LCF system [GMW] one can de­fine the identity function - it takes the form id = AX.X and has the polymorphic type * -+ *, meaning that it maps an element of arbitrary type * into an element of the same type *. Nev­ertheless, there is a strict regime governing type correctness of programs that prevents many involuntary errors. ("Polymorphic" means "having many forms" and, indeed, polymorphic functions appear in many languages but in the role of second-class citizens. For instance, the function new in Pascal is polymorphic since it returns a pointer of arbitrary type. The term was apparently invented by Christopher Strachey and is distinct from "overloading" such as occurs in the use of "+" to denote both integer and real addition [Mill).

In spite of its undoubted advances there are still shortcomings in the type-definition mechanism inML (and in Standard ML [Mi2l). One such is that, for example, the addition and multiplication functions on integers both have the same type int x int -+ int as does the integer division function, div. There is, thus, no mechanism in the ianguage to record the different algebraic properties of addition and multiplication (the fact that 0 is the identity~ of the former and 1 the identity of the latter, etc.); nor is there any mechanism (in the type structure) to indicate that addition and multiplication are everywhere-defined functions whereas integer division is undefined when its second argument is zero.

Another shortcoming of the type-mechanism in ML is that there is no notion of a de­pendent type, in which components of a type may depend on the values held by previously­defined types. An example of a dependent type is the type semigroup. An element of the type semi group is a set 5, say, together with an associative binary operator +, say, defined on the elements of 5. The point to note about this definition is that a semi group has two components, the second of which has type 5 x 5 -+ 5 which depends on the set, 5, defined in the first component.

The third topic on my list, 'logic programming, is often identified with programming in Prolog.. Prolog allows statements to be made in a limited form of the predicate calculus called Horn-clause form. Horn clauses are interpreted procedurally so that a set of one or more clauses describes a set of one or more recursive procedures.

There is no doubt that Prolog has achieved a great deal in highlighting the value of formal logic to programming; my reference to logic programming is, however, to a rather broader understanding of the nature of programming as a mathematical activity requiring an unusual degree of formality and rigour.

The final topic on my list, program verification, is for me the most fundamental. But, although its development began about the same time as the development of data-structuring techniques, it is probably the topic that has had the least effect on the way that practising

2

Page 4: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

programmers develop software. Its effects have been emasculated because the techniques of program verification have never been properly integrated into a programming language. It is still possible to write programs without having the slightest clue about program proofs, in­variant properties etc. and those few programmers who do have such knowledge often regard program proofs as a gross incumbrence and impossible to use except for "toy" problems.

I amimpressed by Martin-Lof's theory because it seems to combine within the same framework many of the advances I have been discussing. It is a logical system, developed from Gentzen's system of natural deduction [Gel, that formalises constructive mathematics in the style of Bishop [Bi]. It incorporates very powerful type-definition facilities, including the notion of dependent types mentioned earlier and it embodies an extremely important principle, the so-called principle of "propositions as types".

In Martin-Lof's theory propositions are identified with types or specifications, and pro­grams are identified with proofs. For example, for an arbitrary type A, the proposition A => A (A "implies" A) is identified with the type A ~ A of all total functions mapping objects of type A into objects of type A. A proof of the validity of A =>A would be accom­plished by exhibiting the identity function AX.X. Thus, in type theory the construction of a proof and the construction of a program are one and the same thing, and it is no longer the case that one is a tiresome and unnecessary addendum to the other. Moreover, the type structure described by the theory is sufficiently rich that it can be usefully used as the basis for a practical specification language.

These notes are an attempt ~o present the theory from a computing scientists perspective. For this reason, I have taken extreme liberties both with notation and presentation, so much so that the uninitiated may not be able to recognise the original. The notes proceed rather slowly at first and it may be some time before the reader sees any "real" examples. Moreover, the early sections stress the formality of the system. I make no apoligies; take it or leave it.

3

Page 5: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

1. Propositions as Types We begin our account of Martin-Lof's theory by explicating the notion of "propositions as types". This is an important notion that originated in the development of intuitionistic logic [M-L2]. It is not an easy notion to grasp and its full explanation extends beyond this section.~

In outline, Martin-Lof's theory is a formal system for making judgements about certain well-formed formulae. Such judgements take one of four possible forms, the most important - to us - being the forms

pEP

A judgement of the form pEP can be read in several different ways. In the conventional computing science sense it is read as "p has type P", or "p is a member of the set P". For example, we write 0 EN meaning "zero has the type natural number", or "zero is a member of the set of natural numbers". In intuitionistic logic it admits a different reading. If P is a proposition (i.e. a well-formed formula constructed from the propositional connectives /\, V

etc.) then the judgement form pEP means that p is a summary of a (constructive) proof of P. This section contains a large number of examples to illustrate this reading. Finally, we shall also see that propositions may be regarded as problem specifications. In this sense the judgement form pEP may be read as "p is a program that achieves the specification " P". Examples of this interpretation of the judgement form do not emerge until section??? We use whichever of the four readings seems natural or appropriate at the time. We also use the more neutral terminology "p is an object of P" when no particular interpretation is intended. .

This identification between objects of a type, proofs of propositions, and programs achiev­ing specifications is an extremely attractive idea relying on a constructive, rather than classi­cal, interpretation of the propositional connectives. Readers familiar with classical accounts

, of the propositional and predicate calculi should not be put off by this, but it may help to interpose some brief remarks on the difference between constructive and non-constructive proofs.

Implicit in any constructive proof of a proposition is an algorithm that constructs a witness to the truth of the proposition. For example, a constructive proof of the statement that there are infinitely many primes must (implicitly or explicitly) show how to construct an infinite sequence of primes. The following "classical" proof given by Courant and Robbins [CR] is non-constructive.

"The proof of the infinitude of the class of primes as given by Euclid remains a model of mathematical reasoning. It proceeds by the "indirect method". We start with the tentative assumption that the theorem is false. This means that there would be only a finite number of primes, perhaps very many - a billion or so-.r;- or, expressed in a general and non~commital way, n. Using the subscript notation we may denote these primes by PI, P2, ... , Pn. Any other number will be composite, and must be divisible by at least one of the primes PI, P2, ... ,Pn. We now produce a contradiction by constructing a number A which differs from everyone of the primes PI, P2, ... ,Pn

4

Page 6: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

"

because it is larger than any of them, and which nevertheless is not divisible by any of them. This number is

A = PIP2,,,Pn + 1,

i.e. 1 plus the product of what we supposed to be all the primes. A is larger than any of the p's and hence must be composite. But A divided by PI or by P2, etc., always leaves the remainder 1; therefore A has none of the p's as a divisor. Since our initial assumption that there is only a finite number of primes leads to this contradiction, the assumption is seen to be absurd, and hence its contrary must be true. This proves the theorem."

The proof is non-constructive because A mayor may not be prime, and therefore a method has not been given for continuing the sequence beyond Pn. However, as Courant and Robbins observe, it can easily be converted into a constructive proof.

"Although this proof is indirect, it can easily be modified to give a method for constructing, at least in theory, an infinite sequence of primes. Starting with any prime number, such as PI = 2, suppose we have found n primes PI,P2, ... ,Pn; we then observe that the number PIP2 ... Pn + 1 either is itself a prime or contains as a factor a prime which differs from those already found. Since this factor can always . be found by direct trial, we are sure in any case to find at least one new prime Pn+l; proceeding in this way we see that the sequence of constructible primes can never : end."

Note that the transformation of the non-constructive proof into a constructive proof hinges on the fact that one can always test whether A is or is not prime. The statement that A is either prime or is not prime is an instance of the law of the excluded middle.

In constructive mathematics the law of the excluded middle is not universally valid. That is, if P is an arbitrary proposition it is not the case that P V ...,p is necessarily true. For such a statement to be true it is required that a constructive proof of P or of -,p be supplied, together with information as to which has been proved. In other words, as in the case of the primality of A, we have to provide a method for testing the truth or falsity of P.

Another example of the role of the law of the excluded middle in constructive proofs arises from the following proof of the pigeon-hole principle [PRLj. The principle can be formulated as "given a function f from the interval {I ... m} into the interval {I ... n}, where n < m, then there exist i and j such that 1 ~ i < j ~ m and f(i) = f(j)". A classical proof uses proof by contradiction. Assume that n < m and, for all i,j such that 1 ~ i < j ~ m, f(i) # f(j)· Then it is also the case that, for all i,j, such that 1 ~ i < j ~ n, f(i) # f(j). Clearly, therefore, for each k, 1 ~ k ~ n, there is some i such that 1 ~ i ~ n, and f(i) = k. In particular, there is some i, 1 ~ i ~ n such that f(i) = f(n+1). This contradicts the initial assumption which must therefore be invalid. We thus conclude the pigeon-hole principle ..

The proof is non-constructive because no method is exhibited for computing distinct i and j in the range {I ... m} for which f( i) = f(j)· However, consider the following instance of the law of the excluded middle. "For all f : {I ... m} -7 {I ... n} it is the case that f(i) # f(j) for all distinct i and j or it is not the case that f(i) # f(j) for all distinct i and j". A constructive proof of this proposition will entail an algorithm to determine

5

Page 7: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

distinct i and j for which f( i) = fU), if such exist. Using such an algorithm our earlier non­constructive proof becomes constructive: apply the algorithm to determine whether distinct i and j in the range 1 ... n exist for which f(i) = fU). If such i and j exist, exhibit them as witnesses to the pigeon-hole principle. If not, exhibit the pair whose first component is n + 1 and whose second component is the value i in the range 1 ... n satisfying f(i) = f(n + 1).

The standard example of a non-constructive proof is the following. The proposition is "there exists a pair of irrational numbers a and b such that ab is rational". The proof is to consider .J2v'2. If this is rational then let a = .J2 and b = ../2. If it is not rational then it is irrational, and since h/2v'2)v'2 = (../2)2 = 2, the assignment a = ../2'1'2 and b = ../2 satisfies the proposition. Thus in either case we have exhibited a pair of irrational numbers a and b such that ab is rational. This proof is non-constructive because we have no way of telling whether the pair (../2, ../2) or the pair (../2'1'2, ../2) satisfies the proposition.

Consider now the proposition "(for all numbers a and b) either ab is rational or ab is irrational". A constructive proof of this proposition is effectively a method (or algorithm) for determining, for arbitrary numbers a and b, whether ab is rational or irrational. Were such an algorithm available, in particular had we a proof that ../2'1/2 is rational or had we a proof that ../2'1'2 is irrational, then the earlier "non-constructive" proof of the existence of irrational numbers a and b for which ab is rational would indeed be constructive. In this case, however, it is believed that there is no general algorithm for resolving whether a given real number is rational or irrational, and the particular case of ../2'1'2 is (to my knowledge) as yet unresolved.-

These examples have been included to assuage the reader's fears that intuitionistic rea­soning is awkward. It is certainly not the case that the law of the excluded middle is never valid. We refer to a proposition P for which a constructive proof of P V ..,p can be proved as a Boolean or decidable proposition. When working with such propositions, classical rea­soning is perfectly acceptable. Moreover, we shall formulate several programming problems as instances of the law, thus taking advantage of its absence.

6

Page 8: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

1.0 Preliminaries. Making a start on a new topic is always difficult, both for -authors and for students, since any (start' is never truly a beginning but relies on some minimal, shared understanding. Making a start on the philosophical foundations of mathematics, which was Martin-Lof's objective, is especially difficult. I shall make a start by simply asking the reader to take for granted, at least throughout this first section, a number of apparently ad hoc rules. The sole purpose of introducing them now is so that we can quickly progress, in a completely formal way, to non-trivial examples; all the rules in this section will be introduced again in a more appropriate context. (In so doing, however, I am aware that I shall be criticised by at least one referee for not discussing immediately whether there is a type of all types - but such a discussion will have to wait until much later.)

We assume that the reader is familiar with the use of types and the notion of scope in conventional programming languages. We also assume knowledge of and experience with the A-notation for naming functions in the A-calculus, the notion of free and bound variables, and the a, (3 and 7] conversion rules. (Stoy's well-known book [St] is more than adequate for our purposes.)

The primitive types in Martin-LOf's theory include the set of natural numbers, denoted A!, and enumerated types like {nil} and {red, yellow, blue}. Formally, we have the rule

(0) A! type

which is read as "A! (the set of natural numbers) is a type". The statement A! type is called a judgement. (There are four judgement forms but only two are considered until section 2.)

The objects of A! are of course 0, 1, 2 etc. For the time being we only need the fact that o is an object of A!, which is written formally as the judgement

(1) 0 EA!

(and read "0 is an object of A!"). Similarly we have the judgements

(2) nil E {nil}

and (3) red E {red, yellow, blue}

The judgement form "p E P" is central to Martin-Lof's theory and can be read as ((p is an object of P" or "p has type P". (As mentioned earlier, we also interpret it in other ways.)

The primitive types are objects of a universe of types denoted by U1• (As the notation suggests there is, in fact, a hierarchy of universes UI, U2, ... but this need not trouble us just yet.) The universe, Ul, is itself a type so we have the judgements

(4) U1 type

and (for example)

(5) A! E Ul

Already, by introducing U1 at this stage, we have diverged from Martin-Lof's preferred order of presentation of his theory. Indeed, in the theory a judgement of the form P type has a rather precise meaning to do with knowing how to form objects of P, and with knowing

7

Page 9: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

when two objects of P are equal. Since we haven't said how to form objects of U1, and we have deliberately postponed the consideration of equalities until much later in the text, we must ask the reader's forbearance in accepting half-formed notions until they can be explained properly. For now, we have a rather shallow understanding of the judgement P type as meaning simply that P is a well-formed formula, or P is a syntactically-correct type expression.

Our first example of an inference rule is the following.

PE Ul Ul-e1imination

P type

The rule states that if P is an object of Ul then P is a type. Using it we can infer (0) from (5) as follows:

o

1

NE Ul %0, Ul-elim. %

N type

The two steps 0 and 1 form a proof-derivation. The numbering of steps and the expla­nations enclosed within percent signs are not part of the derivation but appear only as aids to the reader.

Terminology. Objects of U1 are generally referred to as the small types. Thus N is a small type. We shall adopt this terminology from now on.

8

Page 10: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

1.1 Assumptions and Scope An important aspect of the theory is the ability to make hypothetical judgements, that is judgements that depend on certain assumptions. An assumption is introduced using the following rule of inference.

P type Assumption

I[ x E P [>

II

In the inference part of this rule the symbol x denotes a variable and can be any identifier, sign or mark that does not occur free in P. (It should however be readily distinguishable from other syntactic marks in the language.) The brackets 1 [ and] 1 delimit the scope of the assumption and are pronounced "scopen" and "sclose", respectively.

The two occurrences of P stand for arbitrary expressions. In a valid use of the rule they must be replaced by definitionally equal expressions. For the moment you may read· "definitionally equal" as identical but it has a broader meaning. (For example we shall shortly introduce a number of abbreviations; an expression and its abbreviation are the,n said to be definitionally equal.)

We verbalise the rule as the statement that if P is a type it is permissible to introduce a new context (delimited by the scope brackets) in which it is assumed that x is an object of P.

Assumptions look like variable declarations in conventional programming languages (par­ticularly if one uses begin and end instead of I[ and]l), and there is no harm in adopting this view. Indeed, a vital (meta-) rule of the formal system is that any use of a variable must be within the scope of a declaration of the variable.

Example 1.0

I[ A E U1

[> A type

11

In a context in which A is assumed to be a small type (an object of U1), A is a type.

Derivation

o U1 type % 0, assumption %

1.0 I[ A E U1

t> % 1.0, U1-elim. % 1.1 A type

]I

9

Page 11: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Step 0 is a statement of the primitive rule that Ul is a type. This enables the use of the assumption rule, in step 1.0, to introduce a context in which A is assumed to be a small type. Note that step 1.0 simultaneously introduces the selose bracket at the" end of the derivation.

(End of example)

NB. The use of scope brackets in these notes is the most radical departure from Martin-Lof's system. The difference is one of presentation, and not of semantics, but it is a difference that I regard as very important. For illustrations of Martin-Lof's style of proof derivation see [Be] and [M-L2]. Petersson [Pe] has implemented this style as a replacement for PPLambda in the Edinburgh LCF system [GMW]. For an alternative, top-down, style of proof derivation see the NuPRL system [PRL].

10

Page 12: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

1.2 Type Formation Rules In this section we present a number of type-formation rules - rules for making judgements of the form P type. We also take the opportunity to introduce informally the notion of propositions as types. In presenting the rules -here and elsewhere - I use P, Q, R to denote type expressions, p, q, r, S to denote object expressions and w, x, y, z to denote variables.

(a) Implication

P type I[ x E P t> Q type

11

P :::} Q type :::}-formation

The :::}-formation rule has two premises. The first premise is that P is a type. The second premise is that in a context in which it is assumed that x is an object of P it is possible to prove that Q is a type. If these two premises are satisfied then it is possible to infer that P :::} Q is a type. (Note that the conclusion is read as (P :::} Q) is a type, not P :::} (Q is a type). Viewed as a unary operator, the keyword type has lowest precedence. )

The rule is said to discharge the assumption, x E P, in the second premise, and x is not in scope in the conclusion. As a consequence, the expression Q cannot contain any free occurrences of x since, otherwise, the scope rule would be violated.

The complicated second premise permits the use of conditional or nonstrict implication in type expressions. For example, the expression (Vn E N)(O f. n :::} 0 div n = 0) * is a valid type expression even though 0 div n is undefined when 0 = n. This is a matter that we will return to in sections 2 and ?? For now, the :::}-formation rule is unnecessarily complicated for our purposes and we shall assume the following, simpler formation rule.

Example 1.1

P type Q type

P :::} Q type

I[ A E U1

t> A:::} A type

II

(simplified ):::}-formation

In a context in which A is a small type, A :::} A is a type.

* The conventional notation for universal quantification has been used here. The notation actually used in these notes is somewhat different.

11

Page 13: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

o U1 type

1.0 I[ A E U1

c> % U1-elim. % 1.1 A type

% 1.1,1.1, =>-form. % 1.2 A => A type

]I

(End of example)

In constructive mathematics, a proof of A :::}- B is a method of proving B given a proof of A. Thus A :::}- B is identified with the type A -+ B of (total) functions from the type A into the type B. Assuming that A is a small type, an elementary example would be the proposition A :::}- A. (We use the words proposition and type interchangeably here and elsewhere.) A proof of A :::}- A is a method of constructing a proof of A given a proof of A. Such a method would be the identity function on A, AX.X, since this is a function that, given an object of A, returns the same object of A.

Example 1.2

I[ A E U1

I> I[ B E Ul I> A:::}- (B :::}- A) type

II II

In a context in which A and B are both small types, A:::}- (B :::}- A) is a type.

Derivation

o U1 type

1.0 I[ A E U1

I> % U1-elim. % 1.1 A type

1.2.0 I[ BE U1

I> % U1-elim. % 1.2.1 B type

% 1.2.1,1.1, =>-form. % 1.2.2 B => A type

% 1.1, 1.2.2, =>-form. % 1.2.3 A=> (B => A) type

11 11

(End of example)

The proposition A :::}- (B :::}- A) provides a second, slightly more complicated, example of the constructive interpretation of implication. Assuming that A and B are small types, a proof of A :::}- (B :::}- A) is a method that, given a proof of A, constructs a proof of B :::}- A. Now, a proof of B :::}- A is a method that from a proof of B constructs a proof of A. Thus,

12

Page 14: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

given that x is a proof of A, the constant function Ay.X is a proof of B ::} A. Hence the function )..x.)..y.x is a proof of A ::} (B ::} A). (The function )..x.)..y.x is known as the K-combinator (see e.g. [St,Tu)).)

(b) Conjunction

P type

I[ x E P t> Q type

] 1

P 1\ Q type

I\-formation

Apart from the change of symbol from::} to 1\ there is no difference in the formation rules for implication and conjunction. The complicated second premise permits the use of a conditional or non-strict conjunction (sometimes denoted cand in programming languages). As before, we shall for the time being assume a simpler formation rule as follows:

P type

Q type (simplified) I\-formation

P 1\ Q type

Example 1.3

I[ A E U1

t> I[ B E U1

t> A 1\ B ::} A type

]1

11

In a context in which A and B are small types, A 1\ B ::} A is a type.

Derivation

o U1 type 1.0 I[ A E U1

t> % U1-elim. % 1.1 A type 1.2.0 I[ BE U1

t> % U1-elim. % 1.2.1 B type

% 1.1,1.2.1, A-formation % 1.2.2 A 1\ B type

% 1.1,1.2.2, =>-form. % 1.2.3 A AB=> A type

II II

(End of example)

13

Page 15: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

The proposition A AB::::} A is true in classical mathematics and in constructive mathe­matics. The constructive proof goes as follows: Assume that A and B are small types. We have to exhibit a method that given a pair (x, y), where x is an object of A and y is an object of B, constructs an object of A. Such a method is clearly the projection function fstA,E that projects an object of A A B onto its first component.

Another example of a constructive proof involving conjunction is the proof of the propo­sition A AB::::} B A A. Such a proof is a function that with argument an ordered pair (x, y) of objects x, y in A, B, respectively, reverses their order to construct the pair (y, x).

(c) Disjunction

P type Q type

P V Q type V-formation

A constructive proof of P V Q consists of either a proof of P or a proof of Q together with information indicating which of the two has been proved. Thus P V Q is identified with the disjoint sum of the types P and Q. That is, objects of P V Q take one of the two forms inl x or inr y, where x is an object of P, y is an object of Q, and the reserved words inl (inject left) and inr (inject right) indicate which operand has been proved.

- As elementary examples of provable propositions involving disjunction we take A ::::} A V A, A ::::} A V B and A vB::::} B V A, where A and B are assumed to be small types. There are two possible proofs of A ::::} A V A. The first, Ax.inl x, maps an argument x of type A into the left operand of A V A, and the second, Ax.inr x, maps an argument x of type A into the right operand of A V A. In a proof of A ::::} A V B there is no choice but to map an object x of A into the left operand of A V B. Thus the proof takes the form Ax.inl x. A proof of A vB::::} B V A must map an argument w, say, of type A V B into B V A. This is achieved by examining w to discover whether it takes the form inl x or whether it takes the form inr y. In the former case w is mapped into inr x, in the latter case w is mapped into inl y. Thus, in the notation introduced later, a proof of A vB::::} B V A is Aw.when(w, x.inr x, y.inl y).

Note that the V-formation rule does not permit the use of conditional disjunction. The reason is that the conventional meaning of A cor B assumes the law of the excluded middle - A cor B is true if A is true or A is false and B is true. It is of course feasible in type theory to define A cor B for Boolean types A, but this is not a primitive notion.

Exercise 1.0 Prove the following

I[ A E U1

t> I[ B E U1

t> A vB::::} B V A type

11 11

(End of Exercise)

14

Page 16: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(d) Universal Quantification

P type I[ x E P t> Q(x) type

II

V(P, x.Q(x)) type V-formation

The V-formation rule also has two premises, but now the complication in the second premise is of unavoidable importance. The first premise states simply that P is a type. The second premise is that, in a context in which it is assumed that x has type P, it is the case that Q(x) is a type. The conclusion is that V(P,x.Q(x)) (pronounced "for all P x it is the case that Q(x)") is a type.

Typically Q (x) will be an expression containing free occurrences of the variable x. Such occurrences become bound in the expression V(P,x.Q(x)). Note that the introduction of a binder accompanies the discharge of an assumption. (Compare the V-formation rule with the =?-formation rule. In the former the variable x becomes bound by V, and it is therefore legitimate - and usual- for Q(x) to contain free occurrences of Xi in the latter there is no binder for x and hence, to comply with scope rules, Q must not contain free occurrences of x.)

We prefer the notation V(P,x.Q(x)) to the more conventional (Vx E P)Q(x) because it makes clear the scope of the binding of the variable x. An expression of the form x.R is called an abstraction. Q(x) is called a family of types dependent on x.

In order to prove constructively the proposition V( P, x. Q (x)) it is necessary to provide a method that, given an object p of type P, constructs an object of Q(p). (The notation Q(p) denotes the result obtained by replacing all free occurrences of x in Q(x) by p.) Thus proofs of V(P,x.Q(x)) are functions (as for implication), their domain being P and their range, Q(p), being dependent on the argument p supplied to the function. The fact that the range depends on the argument is what distinguishes universal quantification from implication.

Example 1.4 V(U1 , A.A => A) type

Derivation

o U1 type % Example 1.1 %

1.0 I[ A E U1

1.1 t> A ~ A type

11 % 0,1, V-form. %

2 V(Ul, A.A ~ A) type

(End of example)

According to the semantics of V and =>, a proof of V(U1, A.A => A) is a function that takes a small type A as argument and returns a function mapping A into A. Such a function

15

Page 17: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

is the polymorphic identity function )'A.)'x.x. This function maps a small type A into the identity function on A.

Another example of a polymorphic function is the K-combinator )'A.)'B.).x.).y.x which proves the proposition V(UI,A.V(UI,B.A => (B => A))) - it is a function that takes two types A and B as arguments and returns a proof of A => (B => A), which we recall from section (a) is the function ).x.).y.x.

(e) Existential Quantification

P type I[ x E P t> Q(x)type

II

:l(P, x.Q(x)) type :l-formation

The :l-formation rule is identical to the V-formation rule in that :l binds free occurrences of x in the expression Q(x). (The notation we use for existential quantification takes the same form as that for universal quantification rather than the conventional (:lx E P)Q(x).)

Example 1.5 :l(UI, A.A) type

Derivation

o Ul type 1.0 I[ A E Ul

t> % Ul-elim. % 1.1 A type

II % 0,1, 3-form. %

2 3(Ul, A.A) type

(End of example)

A constructive proof of :l(P, x.Q(x)) consists of exhibiting an object p of P together with a proof of Q(p). Thus proofs of :l(P, x.Q(x)) are pairs (p, q) where p is a proof of P and q is a proof of Q(p).

The type :l( P, x. Q (x)) is called a dependent type because the second component, q, in a pair (p, q) in the type depends on the first component, p (and thus distinguishes it from P 1\ Q). This is illustrated by our example. There are many objects of the type :l(UI , A.A). E(1,ch consists of a pair (A, a) where A is a small type and a is an object of that type. (Thus the proposition is interpreted as the statement "there is a small type that is provable", or "there is a small type that is non-empty".) For example, (N,O) is an object of :l( UI , A.A) since N is a small type (an object of UI ) and 0 is an object of N. Two further examples are ({red, yellow, blue}, red) and (N => N,).x.x).

Objects of the type :l( UI , A.A) are the simplest possible examples of algebras (one or more sets together wi th a number of operations defined on the sets) since they each consist of a set A together with a single constant of A. A slightly more complicated algebra is specified

16

Page 18: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

by the type :J(U1 , A.A /\ A::::} A). An object of this type consists of a small type A together with a single binary operation defined on A. As yet, however, we cannot specify equational properties of algebras, for example the associativity of multiplication in a semigroup.

(f) Negation

Negation is not a primitive concept of type theory. It is defined via the empty type. The empty type, denoted 0, is the type containing no elements. Its formation rule is very simple.

0-formation o type

Moreover, 0 is a small type.

U1-introduction o E U1

The negation -,p is defined to be P ::::} 0.

-,p == P ::::} 0

(= stands for definitionally equal to.) This means that a proof of -,p is a method for constructing an object of the empty type from an object of P. Since it would be absurd to construct an object of the empty type this is equivalent to saying that it is absurd to construct a proof of P.

As an example of a provable negation, consider the proposition -,V(Ul' A.A). The propo­sition states that not every small type is provable, or not every small type is non-empty. The basis for its proof is very ordinary - we exhibit a counter-example, namely the emptytype 0. Formally, we have to construct a function that maps an argument f, say, of type V( Ul, A.A) into 0. Now f is itself a function mapping objects, A, of Ul into objects of A. So, for any small type A, the application of f to A, denoted fA, has type A. In particular, f0 has type 0. Thus the proof object we require is )..f.f0.

(g) Families of Types

An important concept in the theory - that has already been illustrated in several ways - is that of a family of types. For example, A ::::} A is a family of types that includes the particular instances ~ ::::} ~ and N ::::} N. Generally we say that R is a family of types indexed by x E P if the judgement R type can be made in a context in which x is assumed to be an object of P.

The rich type-definition mechanism is reflected in the construction of such families of types. Further examples (with hopefully obvious meanings) are

case x IS

male ~ {Bill, J oe} female ~ {Mary, Jane} )

indexed by x E {male,female}, and

17

Page 19: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

when x is inl a -+ C inr b -+ {error}

indexed by x E A V B. The first example has two instances (a) {Bill, loe} and (b) {Mary, lane}. The second example also has two instances (a) C and (b) {error}. Such dependent type structures have obvious programming applications: we might use the first type structure to specify a database in which the names of males and females are taken from different sets; the second example might be used to specify a function that returns a value of type C when its argument is of one type and returns error when its argument is of another type (eg. the function div).

The notion of a family of types is central to many of the inference rules in the theory but, for reasons that do not emerge until section 2 and are not completely resolved until section 3, the examples given in this section are grossly impoverished in this respect. This isn't a major disadvantage in a tutorial presentation but the reader must be prepared to wait for section 2 before the full generality of the rules can be illustrated.

18

Page 20: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

1.3 Introduction and Elimination Rules For some time now, computing scientists have recognised the need for program structure to reflect data structure. In the words of C.A.R. Hoare [HoJ

"There are certain close analogies between the methods for structuring data and the -methods for structuring a program which processes that data. Thus, a Cartesian product corresponds to a compound statement, which assigns values to its compo­nents. Similarly, a discriminated union corresponds to a conditional or case con­struction, selecting an appropriate processing method for each alternative ... "

This has had an important influence on program design methodologies, a notable example being Jackson's program design method [JaJ.

In Martin-Lof's theory the "analogy" between data structure and program structure is made explicit. With each type constructor is associated zero or more so-called introduction rules together with a single elimination rule. The introduction rules show how to construct the primitive objects of the type; they thus define the data structure. The elimination rule shows how to manipulate or "destruct" objects of the type.

In Martin-LOf's terminology, the introduction rules define canonical objects and the elimination rules define non-canonical objects. The canonical objects of a type are the primitive objects of the type in the sense that they may be viewed as programs that have ~hemselves as value. The non-canonical objects are not primitive; for each non-canonical object a computation rule is supplied that shows how to evaluate the object.

The terminology "introduction rule" and "elimination rule" is borrowed from Gentzen's account of natural deduction [GeJ. Indeed, the form of Martin-Lof's rules for the propo­sitional connectives follows closely the form of Gentzen's rules. Martin-Lof's contribution has been to add proof objects which summarise the steps used to establish a proposition and which can be given computational meaning. Some familiarity with proofs in Gentzen's system may therefore be helpful to the reader.

In this section we exhibit the introduction and elimination rules for the propositional connectives, and use them to establish a number of familiar tautologies of the (class\,cal) propositional calculus. Verbal descriptions accompanying the examples interpret them both in a logical sense and in a computational sense.

Throughout this section we assume that A, Band C are small types. Formally, we write

I[ A,B,C E U1

The sclose terminating the scope of these assumptions will be found at the end of the section. The notation I[ A, B E U1 [> JI is just an ad hoc abbreviation for I[ A E U1 [>

I[ BE U1 [> JI JI·

(aJ Implication

Our first rule is the introduction rule for implication.

19

Page 21: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(premises of :}-formation) I[ x E P t> q(x)EQ ]I

AX.q(X) E P :} Q :}-introduction

In a logical sense the rule may be read as "if assuming that x is a proof of P it is possible to construct a proof of Q then AX.q( x) is a proof of P => Q". In a computational sense the rule is read differently. "If in a context in which x is an object of type P the object q(x) has type Q then the function AX.q(X) is an object of type P :} Q".

In general, q(x) will be an expression containing zero or more free occurrences of x. Such occurrences of x become bound in the expression AX.q(X). As we remarked earlier, binding of variables is always associated with the discharge of assumptions.

Note Martin-Lof omits several premises in his presentation of the inference rules and this has led to several misunderstandings and errors. In particular, in a rule with inference of the form pEP he omits premises of the form P type. Other authors have tried to remedy this by specifying a minimal set of additional premises. I prefer the more systematic approach of simply prefacing each rule with a reminder of the missing premises. Thus, it can be argued that the premises of :}-formation are all superfluous in the above rule; however, such premises are essential to the correct applic~tiono( later rules.

Example 1.6 AX.X EA:::} A

This is a continuation of example 1.1. We now show formally how to derive the judgement that the identity function is a proof of the proposition A=? A.

Derivation

0.0 I[ x E A t> % 0.0 %

0.1 x E A

)1 % Example 1.1,0, =>-intro. %

1 Ax.xEA=>A

Note that the numeral 0 in the explanation of step 1 stands for the combination of the assumption 0.0 and the conclusion 0.1. Example 1.1 is quoted in the explanation of step 1 because it includes the required premises of the form P type.

(End of example)

Example 1.7 AX.Ay.X EA=? (B :} A)

Derivation

20

Page 22: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

0.0 I [ xEA 0.1.0 I> I[ yE B

I> %0.0 % 0.1.1 xEA

1I % Example 1.2,0.1, =>-intro. %

0.2 )..y.x E B => A

]I % Example 1.2, 0, =>-intro. %

1 )..x.)..y.x EA=> (B => A)

(End of example)

The :::}-elimination rule is easily recognisable as the rule of modus ponens.

(premises of :::}-formation) pEP rEP:::}Q

:::}-elimination rp E Q

In a logical sense the rule states that if p is a proof of P and r is a proof of P :::} Q then rp is a proof of Q. In a computational sense it states that if p has type P and r is a function from P to Q then rp, the result of applying r to p, has type Q.

The notation we are using for A-expressions and function application is the conventional one [Stj. That is, function application is denoted by juxtaposition and associates to the left, and we assume that when a A-term such as AX.q occurs in a larger expression qis taken as extending as far as possible - to the first unmatched closing bracket or the end of the expression, whichever is first. Corresponding to the convention that function application associates to the left we have the convention that implication associates to the right. Thus P :::} Q :::} R is read as P :::} (Q :::} R). Occasionally, but not always, we use this convention to reduce the number of parentheses. However, we prefer to retain the parentheses when it makes the import of the examples and exercises clearer.

Example 1.8 Af.Ag.AX.g(fX) E (A:::} B) :::} (B :::} C) :::} (A:::} C)

The example asserts that implication is transitive. I.e. given a proof f of A:::} B, and given a proof 9 of B :::} C, the object AX.g(fX) is a proof of A:::} C.

Derivation

In the following derivation we omit judgements such as A:::} B type, B :::} C type. Strictly, these are necessary to the use of the assumption rule and the :::}-introduction rule but their inclusion would obscure the main details.

21

Page 23: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

0.0 1 [ fEA~B

0.1.0 I> 1 [ gEB~C

0.1.1.0 I> I[ x EA I> % 0.0, 0.1.1.0, ~-elim. %

0.1.1.1 fx E B % 0.1.0, 0.1.1.1, ~-elim. %

0.1.1.2 g(lx) E C ]I

% 0.1.1 ~-intro. % 0.1.2 >.x.g(lx) E A ~ C

II % 0.1, ~-intro. %

0.2 >.g.>.x.g(lx) E (B ~ C) ~ (A ~ C)

II % 0 ~-intro. %

1 >.f.>.g.>.x.g(lx) E (A ~ B) ~ (B ~ C) ~ (A ~ C)

(End of example)

Exercise 1.1 Verify the following.

(a) >.f.>.g.>.x.fx(gx) E [A => (B => C)] => [(A => B) => (A => C)] (b) >.f.>.x.>.y.f(>.z.y)x E [(A => B) => (A => C)] => [A => (B => C)] (Equivalence is defined as the conjunction of two implications. Exercise 1.1 is therefore a proof that implication distributes over implication. I.e.

[A => (B => C)] ~ [(A => B) => (A => C)]. )

Exercise 1.2 Prove, and construct proof objects for, the propositions: (a) (A => B => C) => (B => A => C) (b) (B => C) => (A => B) => (A => C) (c) [((A => B) => B) => B] => [A => B] (d) A => ((A => B) => B)

(End of exercise)

Note: Example 1.7, exercise 1.1(a) and exercises 1.2(a) and (b) are motivated by the K, 5, B and C combinators [Tu]. See later for more general forms of 5 and K. Exercises (c) and (d) are discussed again in section 1.3(f).

(b) Conjunction

The semantics of conjunction in constructive mathematics identifies P /\ Q with the Cartesian product P x Q. That is, a proof of P /\ Q is an ordered pair (p, q) where p is a proof of P and q is a proof of Q. The introduction rule is therefore very straightforward.

(premises of /\-formation) pEP

q E Q /\-introduction

(p, q) E P /\ Q

22

Page 24: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Example 1.9 AX.(X, x) EA=} A t\ A

A proof of A t\ A can be constructed from a proof of A simply by repeating the proof object. (Note that conjunction takes precedence over implication in the expression A =} A /\ A.)

Derivation

0.0 I[ x E A c> % 0.0, 0.0, A-intro %

0.1 (x,x) E AAA

11 % 0, =>-intro %

1 AX.(X, x) EA=> A A A

(End of example)

Example 1.10 (Currying)

Af.AX.Ay.f(X, y) E (A t\ B =} C) =} (A =} B =} C)

This is one of my favourite examples of the principle of propositions-as-types. In a logical sense the example is very familiar to all English speakers since it is legitimate to say either "if A and if B then C" or "if A then ifB then C". In a computational sense it also expresses a very familiar rule, namely that any function f of a pair of arguments (x, y) can be "curried" (after Haskel B. Curry), i.e. converted into a function that maps the single argument x into a function that maps the second argument y into the result of applying f to the pair (x, y).

Derivation

0.0 1 [ fEAAB=>C 0.1.0 c> I [ xEA 0.1.1.0 c> I[ yEB

c> % 0.1.0, 0.1.1.0, A-intro. % 0.1.1.1 (x, y) E A A B

% 0.0,0.1.1.1, =>-elim. % 0.1.1.2 f(x,y)EC

]I % 0.1.1, =>-intro. %

0.1.2 Ay.f(x, y) E B => C ]I

% 0.1, =>-intro. % 0.2 AX.Ay.f(X, y) EA=> B => C

11 % 0, =>-intro. %

1 Af.AX.Ay.f(X, y) E (A AB=> C) => (A => B => C)

(End of example)

Many of the propositions we prove have implication as the principal connective. Corre­spondingly, derivations often end with at least one application of the =}-introduction rule. We hope that by now the reader is familiar with this rule and we shall omit it, except in a

23

Page 25: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

few places. We shall also compact several consecutive assumptions into one. As illustration the following is an abbreviation of the last derivation.

Abbreviated Derivation 0.0 I[ f E A /\ B ~ C; x E A; yE B

t> % 0.0, /\-intro. % 0.1 (x,y) EA/\B

% 0.0, 0.1, ~-elim. % 0.2 f(x, Y} E C

II End of abbreviated derivation

The latter derivation may be summarised as the statement that in a context in which f has type A /\ B => C, x has type A and y has type B, it is the case that f(x,y) has type C. This is semantically equivalent to the statement that )..f.)..x.)..y.f(x,y} has type (A /\ B=> C) => (A => B => C).

In Gentzen's system there are two elimination rules for conjunction. The first states that it is possible to infer A from A AB, the second states that it is possible to infer B from A /\ B. Martin-Lof has combined these two rules into one, which takes the following form:

.. (premises of A-formation) I[ wE P /\ Q !> R(w) type

II rEPAQ

I[ x E Pi Y E Q !> S (x, y) E R( (x, y) ) II

/\-elimination . split(r, (x, y).s(x, y)) E R(r)

The first premise states that R( w) is a type in a context in which w is an object of P /\ Q. Typically, therefore, R(w) is a family of types, one for each such object. More precisely, R( w) is a type expression containing an arbitrary number of occurrences of the dummy variable w such that R(r) is a type whenever r is an object of P /\ Q. Given this premise, the rule is used to prove R( r) as follows. First, establish that r has type P /\ Q. Second, assume that x and y are individual objects of P and Q, respectively, and construct an object s(x,y) of type R((x,y}). Then the exhibited split construct is a proof of R(r). Computationally the split construct has the effect of splitting a pair, r, into its components, the value of the expression s(x, y) is then computed with the components being bound to the variables x and y occurring free in the expression.

The A-elimination rule is one of those that, as yet, we can only illustrate in a limi.ted way. Thus, although the rule permits the type R to depend on the object r, none of the examples in this section illustrate such a dependence.

24

Page 26: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Example 1.11 Aw.split(w, (x,y).x) E A 1\ B => A

The function, fst, which projects a pair onto its first component is the function that splits its argument w into the pair (x, y) and returns x.

Derivation

0.0 I [ wEAAB 0.1.0 t> I [ x E A;y E B

t> % 0.1.0 % 0.1.1 xEA

] I % 0.0, 0.1, A-elim. %

0.2 split(w, (x, y).x) E A

]I

The function, snd, which projects a pair onto its second component is obtained similarly.

(End of example)

Example 1.12 (Uncurrying)

Af.Aw.split( w, (x, y).fxy) E (A => B => C) => (A 1\ B => C)

Derivation

0.0 I[ jEA=?B=?C 0.1.0 t> I[ wEAAB 0.1.1.0 t> I[ x EA; yE B

t> % 0.0, 0.1.1.0, =?-elim. % 0.1.1.1

0.1.1.2

0.1.2

]1 ]1

(End of example)

]1

Ix E B =? C % 0.1.1.0,0.1.1.1, =?-elim. %

jxy E C

% 0.1.0, 0.1.1, A-elim. % split(w, (x, y).fxy) E C

Exercise 1.3 Verify the following: (a) Aw.split(w, (x, y ).(y, x)) E A 1\ B => B /\ A (b) Af.(Ax.fst(JX), Ax.snd(Jx)) E (A => B 1\ C) => (A => B) 1\ (A => C) (c) Aw.split(w, (J,g).AX.(JX,gx)) E (A => B) 1\ (A => C) => (A => B 1\ C)

(End of exercise)

Exercise 1.4 Parts (b) and (c) of the last exercise can be interpreted as the claim that implication distributes over conjunction; part (a) establishes that conjunction is symmetric. Establish as many other algebraic properties of conjunction and implication as you can.

(End of exercise)

25

Page 27: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(c) Disjunction

A proof of P V Q is a proof of P or a proof of Q together with information as to which has been proved. Thus, P V Q is identified with the disjoint sum of P and Q and has two introduction rules.

(premises of V-formation) pEP

inl pEP V Q

(premises of V-formation) q E Q

inr q E P V Q V -introduction

The constants inl and inr are called· injection functions and stand for inject left and inject right, respectively.

Example 1.13 Ax.inl x EA::::} A V A

There are two functions of type A ::::} A V A depending on whether the argument x is injected into the first or second operand of A V A. Our derivation takes the first option.

Derivation

0.0 I[ x E A t> % 0.0, v-intro. %

0.1 inl x E A v A ]I

(End of example)

Example 1.14 Af.Ax.f(inl x) E (A vB::::} C) => (A => C)

Given a function mapping elements of the disjoint union A V B into C it is possible to construct a function mapping A into C. Alternatively, if either A or B implies C then A implies C.

Derivation

0.0 I[ fEAVB~C

0.1.0 t> I[ xEA t> % 0.1.0, v-intro. %

0.1.1 inl x E A v B % 0.0, 0.1.1, :::}-elim. %

0.1.2 f(inl x) E C

II ]I

(End of example)

Exercise 1.5 Verify the following : Af.f(inr(Ax.f(inl X)))E [(A V (A ::::} B)) ::::} Bl => B

(End of exercise)

Example 1.14 and exercise 1.5 are motivated by properties of negation that are considered later in section 1.3(f).

26

Page 28: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

The v-elimination rule corresponds to case analysis as in the following argument. Sup­pose it has been established that just two cases P and Q need to be considered and suppose it is possible to prove R both in the case P and in the case Q. Then R is true in general.

(premises of V-formation) I[ wE P V Q c> R(w) type II rEPVQ I[ x E P C> s(x)ER(inlx)

II I[ yE Q C> t(y) E R(inr y)

JI V -elimination

when(r, x.s(x), y.t(y)) E R(r)

The V-elimination rule is used to prove a proposition R by a case analysis on P or Q. Although we are unable to illustrate the full generality of the rule at this stage, the first premise indicates that, typically, R is a family of types indexed by the (dummy) variable w of type P V Q. We prove R at r ("R(r)" in the inference) by showing that R is provable at inl x whenever x is an object of P and at inr y whenever y is an object of Q (cf. the last two premises).

Note that the rule discharges two assumptions. Thus within the when statement the variable x is bound in s(x) and the variable y is bound in t(y).

A when statement is similar to an if statement in conventional languages. Computa­tionally the rule states that if s(x) constructs an object of R(inl x) when supplied with an argument x of type P and if t(y) constructs an object of R(inr y) when supplied with an argument y of type Q then it is always possible to construct an object of R(r) from an object r of P V Q. To do so, examine the form of r and if it is inl p bind x to p and apply s(x), if it is inr q bind y to q and apply t(y).

Example 1.15

)'d.when(d,x.x,x.x) E A V A =} A

An object x of A that is injected into the disjoint sum A V A must either be injected into the left or into the right operand. The exhibited function performs the reverse process.

27

Page 29: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 I[ wE Av A 0.1.0 I> I[ xEA 0.1.1 I> x EA

]I % 0.0, 0.1, 0.1, v-elim. %

0.2 when(w,x.x,x.x) E A

] I (End of example)

Example 1.16

>.w.when( w, f.>.x.f(f st(x)), g.>.x.g(snd(x))) E [(A::} C) V (B ::} C)] ::} [(A /\ B) ::} C]

Derivation

0.0 I[ w E (A => C) v (B => C) 0.1.0 I> I[ f EA=> C 0.1.1.0 I> I[ x EA 1\ B

I> % 0.1.1.0, Example 1.11 % 0.1.1.1 f st(x) E A

% 0.1.0, 0.1.1.1, =>-elim. % 0.1.1.2 f(fst(x)) E C

]I % o.n, =>-intro. %

0.1.2 >..x.f(fst(x)) EA 1\ B => C

II 0.2.0 I[ 9 E B => C

I> % similarly % 0.2.1 Ax.g(snd(x)) EA 1\ B => C

]1 % 0, 0.1,0.2, v-elim. %

0.3 when(w, f.).,x.f(fst(x)), g.).,x.g(snd(x))) EA 1\ B => C

II (End of example)

Exercise 1.6 Prove the following:

(a) AvB::}BvA (b) A V (B V C) ::} (A V B) V C (c) A V (B /\ C) =? [(A V B) /\ (A V C)] (d) A V (B ::} C) =? [(A V B) =? (A V C)] (e) [(A::} B) V (A ::} C)] ::} [A =? (B V C)] (f) [(A =? C) /\ (B ::} C)] =? [(A V B) ::} C]

(End of exercise)

Exercise 1.7 Conjecture some more algebraic properties of /\, V and::} and try to prove them.

(End of exercise)

28

Page 30: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(d) Universal Quantification

We recall from our informal account of the semantics of universal quantification that, like an implication, the type V(P, x.Q(x)) is identified with a function type but that the type of the range, Q(x), may depend on the argument, x. In Martin-Lof's terminology, Q(x) is a family of types, one for each object, x, in A. That is, typically Q(x) will be a type expression containing zero or more free occurrences of x. (Of course such free occurrences become bound in the expression V(P, x.Q(x)) .)

We can infer V(P,x,Q(x)) if it is always possible to establish Q in a context in which it is assumed that x has type P. This is the V-introduction rule.

(premises of V-formation) I[ x E P t> q(X)EQ(x)

JI V-introduction

).x.q(x) E V(P, x.Q(x)) Two binders are introduced when the assumption x E P is discharged. The lambda, ).,

binds the first x in q( x), and, as already mentioned, the universal quantification binds the second x in Q(x).

Example 1.17 )'A.)'x.x E V(UI, A.A ~ A)

A ~ A is a family of types, one for each small type A. The function )'A.)'x.x is the polymorphic identity function.

Derivation 0.0 I[ A E U1

I> % Example 1.6 % 0.1 ).x.x EA=> A

11 % Example 1.4,0, V-intro. %

1 ).A.).x.x E V(U1,A.A => A)

(End of example)

Many examples similar to example 1.17 can now be quoted simply by discharging the assumptions A, B, C E U1 introduced at the beginning of this section. We give just a few.

Example 1.18 (a) )'A.)'B.).x.inl x E V(U1, A.V(U1, B.A ~ A V B)) (b) )'A.)'B.).w.split(w, (x,y).x) E V(Ul,A.V(UI,B.A/\ B ~ A)) (c) )'A.)'B.)'C.).j.).x.j(inl x) E V(U1, A.V(U1, B.V(U1, C.(A V B ~ C) ~ A ~ C)))

(End of example)

29

Page 31: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

The V-elimination rule is almost identical to the =>-elimination rule.

(premises of V-formation) r E V(P, x.Q(x)) pEP

V-elimination rp E Q(p)

If r is a function that given an arbitrary argument x of type P constructs a proof of Q and if p has type P then rp (the result of applying r to p) has type (or proves) Q (p).

Several examples of the properties of universal quantification may be obtained by a straightforward generalisation of properties of implication. For instance:

Example 1.19

1 [ F, G EA=> Ul [> )..f.)..g.)..z.fz(gz) E V(A,x.Fx => Gx) => V(A,y.Fy) =>V(A,z.Gz)

11

This example generalises exercise 1.1( a). (To obtain the latter replace occurrences of "Fx" and "Fy" by "E", "Gx" and "Gz" by "C", and "V(A, x.)", "V(A, y.)", "V(A, z.)"~by "A =>".) We begin by establishing that a number of type expressions are well-formed. Note that judgements 0.2 and 0.4 are prerequisites for the assumptions 0.7.1.0 and 0.7.0, respec­tively. Judgements 0.3, 0.5 and 0.6 are necessary when using =>-introduction to discharge the assumptions 0.7.1.1.0, 0.7.1.0 and 0.7.0, respectively.

30

Page 32: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 I[ F, G EA=!;> U1

0.1.0 C> I[ yEA c> % 0.0, 0.1.0, =!;>-elim. %

0.1.1 Fy E U1

% 0.1.1, U1-elim. % 0.1.2 Fy type

0.2

0.3

004

0.5

0.6 0.7.0 0.7.1.0 0.7.1.1.0

0.7.1.1.1

0.7.1.1.2

0.7.1.1.3

II

]I % A type, 0.1, 'v'-form. %

'v'(A, y.Fy) type % similarly %

'v'(A, z.Gz) type % exercise %

'v'(A, x.Fx =!;> Gx) type % 0.2, 0.3, =!;>-form. %

'v'(A, y.Fy) =!;> 'v'(A, z.Gz) type % 004, 0.5, =!;>-form. %

'v'(A, x.Fx =!;> Gx) =!;> 'v'(A, y.Fy) =!;> 'v'(A, z.Gz) type I[ J E 'v'(A, x.Fx =!;> Gx) c> I[ 9 E 'v'(A, y.Fy)

II

c> I[ z E A

II

c> % 0.7.1.0, 0.7.1.1.0, V-elim. %

]I

gz E Fz % 0.7.0, 0.7.1.1.0, 'v'-elim. %

Jz E Fz =!;> Gz % 0.7.1.1.1, 0.7.1.1.2, =!;>-elim. %

fz(gz) E Gz

In this example we have been careful to use distinct bound variables so as to illustrate the process of substitution in V-elimination. (See steps 0.7.1.1.1 and 0.7.1.1.2.) We shall not be so careful in the future.

(End of example)

A second example will illustrate further the process of generalising implication to uni­versal quantifications. Note particularly in this example the importance of well-formedness of type expressions.

Example 1.20

I[ FE A vB:::} U1

[> >.f.>.x.f(inl x) E V(A V B,w.Fw):::} V(A,x.F(inl x))

II In a context in which F is a family of small types, one element of the family for each

object of AV B, the function >.f.>.x.f(inl x) is a proof ofV(AV B, w.Fw) :::} V(A, x.F(inl x)). This result generalises the proof of the proposition (A vB:::} C) =? A :::} C in example 1.14. The well-formedness of the type expressions is a non-trivial part of the derivation and so

31

Page 33: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

we begin by establishing a number. of judgements of the form P type. Note that judgement 0.2 is a prerequisite to assumption 0.5.0, and judgement 0.4 is a prerequisite to the use of V-introduction in step 0.6.

Derivation

0.0 I[ F E A v B ~ Ul

0.1.0 t> I[ wE A V B t> % 0.0, 0.1.0, ~-elim. %

0.1.1 Fw E Ul

% 0.1.1, Ul-elim. % 0.1.2 Fw type

II % A V B type, 0.1, V-form. %

0.2 V(A vB, w.Fw) type

0.3.0 I[ x E A t> % 0.3.0, v-intra. %

0.3.1 inl x E A V B % 0.0, 0.3.1, ~-elim., Ul-elim. %

0.3.2 F(inl x) type

0.4 0.5.0 0.5.1.0

0.5.1.1

0.5.1.2

0.5.2

0.6

II

1I % A type, 0.3, V-form. %

V(A, x.F(inl x» type

I[ f E V(A V B, w.Fw) t> I[ x E A

II

t> % 0.5.1.0, v-intra. %

II

inl x E A V B % 0.5.0, 0.5.1.1, V-elim. %

f(inl x) E F(inl x)

% 0.4, 0.5.1, V-intro. % Ax.f(inl x) E V(A, x.F(inl x»

% 0.2,0.4, 0.5.0, ~-intro. % Af.Ax.f(inl x) E V(A vB, w.Fw) ~ V(A, x.F(inl x»

(End of example)

From now on we shall omit the verification of the first set of premises (those relating to the formation rule), except in some cases where it is non-trivial or is especially relevant.

Exercise 1.8 Construct proof objects for the following.

(a) (cf. example 1.10) 1 [ H E A /\ B => U1

[> V(AI\B,w.Hw) =>V(A,x.V(B,y.H(x,y)))

II (b) (cf. example 1.12)

I[ H E A 1\ B => U1

[> V(A, x.V(B, y.H(x, y))) => V(A 1\ B, w.Hw)

II 32

Page 34: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(End of exercise)

(e) Existential Quantification

In the same way that universal quantification generalises implication, existential quan­tification generalises conjunction. To prove 3(P, x.Q(x)) it is necessary to exhibit an object p of P and an object q of Q(p). Thus the proof object is a pair (p, q) where now the second component may depend on the first.

(premises of 3-formation) pEP q E Q(p)

(p, q) E 3(P, x.Q(x))

Example 1.21 (N,O) E 3(UI, A.A)

3-introduction

This example illustrates the dependence of the second component on the first. (The inspiration for it came from [BL].)

Derivation

o NE U1

1 0 EN % 0,1, 3-intro %

2 (N,O) E 3(U1 , A.A)

(End of example)

Example 1.22

I[ FE A =* U1

t> Af.AX.Ay.f(X, y} E (3(A, x.Fx) ::} C) =* V(A, x.Fx ::} C) ]1

This generalisation of example 1.10 is obtained by substituting "3(A, x.Fx)" for "AAB" and "V(A,x.Fx" for "A =*(B".

Derivation

0.0 0.1.0 0.1.1.0 0.1.1.1.0

0.1.1.1.1

0.1.1.1.2

I[ FE A => U1

I> I[ f E 3(A, x.Fx) => C

11

I> I[ xEA

11

I> I[ yE Fx

11

I> % 0.1.1.0, 0.1.1.1.0, 3-intro. %

11

(x, y) E 3(A, x.Fx) % 0.1.0,0.1.1.1.1, :::}-elim. %

f(x,y) E C

33

Page 35: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Following the convention introduced earlier with regard to the omission of steps involving the use of ~-elimination, we also omit final steps in a derivation that involve the use of V­introduction.

(End of example)

Exercise 1.9

Fill in all the details in the last derivation. (I.e. include proofs of judgements of the form P type.)

(End of exercise)

The following exercise is a further generalisation of Example 1.10.

Exercise 1.10 Prove the following :

I[ FE A ~ U1 ; G E 3(A,x.Fx) ~ Ul [> >.f.>.x.>.y.f(x, y) E V(3"(A, x.Fx), w.Gw) ~ V(A, x.V(Fx, y.G(x, y))) JI

(End of exercise)

The elimination rule for existential quantification enables one to assume that a proof r of 3(P,x.Q(x)) can be split into two components.

(premises of 3-formation) 1 [ w E 3 ( P, x. Q ( x ) ) [> R(w) type

JI r E 3(P, x.Q(x)) I[ yEP; zEQ(y) [> s(y,z)ER((y,z)) JI

split(r, (y, z).s(y, z)) E R(r) 3-elimination

The first premise states that R( w) is a type in a context in which w is a proof of 3(P,x.Q(x)). Typically, therefore, R(w) is a family of types, one for each object, w, in the existential quantification. Given this premise, one proves R(r) by first establishing that r proves 3(P,x.Q(x)) and, second, establishing R((y,z)) whenever y is an object of P and z is an object of Q(y).

Example 1.23

I[ FE Av E ~ U1

[> 3(A V E, x.Fx) ~ [3(A, a.F(inl a)) V 3(E, b.F(inr b))J

JI

34

Page 36: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 0.1.0 0.1.1.0 0.1.1.1.0

0.1.1.1.1

0.1.1.2

0.1.2.0 0.1.2.1

0.1.3

0.1.4

0.2

% eone abbreviates 3(A, a.F(inl a)) V 3(B, b.F(inr b)) % I[ pE 3(A vB, x.Fx) c> I[ xEAvB;/EFx

c> I[ a E A

II

c> I[ 9 E F(inl a) c> % 0.1.1.0,0.1.1.1.0,3-intro,v-intro %

inl (a, g) E eone ]I

% =>-intro % Ag.inl (a, g) E F(inl a) => eone

]I % similarly %

I[ bE B C> Ag.inr (b, g) E F(inr b) => cone II

% 0.1.0,0.1.1,0.1.2, v-elimination % when(x, a.Ag.inl (a, g), b.Ag.inr (b, g}) E Fx => eone

% 0.1.0, 0.1.3, =>-elimination % when(x, a.Ag .inl (a, g), b.Ag.inr (b, g})/ E eone

% 3-elimination % split(p, (x, f).when(x, a.Ag.inl (a, g), b.Ag.inr (b, g})f) E eone

]I medskip For some time I believed that this example could only be derived with the aid

of the equality rules of section 2. The above proof was however suggested by Erik Saaman. It is an excellent illustration of the use of a family of types in an elimination rule. (Note particularly step 0.1.3; the family of types used here is Fw => cone indexed by w E A V B.) Nevertheless I still find the derivation unsatisfactory since the final proof object contains a, to my mind, spurious A-abstraction and function application. This example has therefore acted as a catalyst for a number of proposed changes to Martin-L6f's rules. For further discussion see [Ba?].

(End of example)

Exercise 1.11

Assuming that F and G have type A => Ul, construct proof objects for the following.

(a) 3(A, x.Fx => C) => V(A, x.Fx) => C (b) 3(A,x.Fx) V 3(A,x.Gx) ~ 3(A,x.Fx V Gx) (c) V(A,x.Fx => Gx) => 3(A,x.Fx) => 3(A,x.Gx)

Assuming that F has type A vB=> Ul, construct a proof object for the following.

(d) 3(A,x.F(inl x)) V 3(B,y.F(inr y)) => 3(A V B,w.Fw) Assuming that F has type A /\ B => U1 and G has type A=> U1, construct proof objects

for the following. (e) 3(A/\ B,p.Fp) => 3(A,a.3(B,b.F{a,b)))

(End of exercise)

35

Page 37: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

( f) Negation

As mentioned earlier, negation is not a primitive of type theory. Instead --,A is modelled by A ::} 0, where 0 is the empty type. I.e. a proof that A is not true is interpreted as a method of constructing an object of the empty type given an object of A.

Several properties of negation arise immediately from earlier examples by substituting o for one of the type variables A, B or C. Specifically, the substitution rule we use is the following.

pEP

I[ x E P t> r(x) E R(x)

II Substitution

r(p) E R(p)

Example 1.24 AX.X E --,0

The identity function maps the empty type to itself. Equally, the identity function is a method of proving that 0 is not true.

Derivation

% U1-intro. % ° 0 E U1

% Example 1.6 % 1.0 I[ A E U1

1.1 t> >.x.x EA=> A

11 % 0,1, A:= 0 %

2 AX.X E 0 => 0

Notes: (a) There is of course a more direct derivation obtained by replacing A by 0 in the derivation

(rather than the result of example 1.6). (b) An assignment statement is used to indicate a substitution. My apologies to ardent

functional programmers but, after all, the semantics of assignment is substitution.

(End of Example)

Some examples of familiar properties of negation are as follows. In each case the property is established by substituting 0 for the type variable C in the relevant example or exercise.

Example 1.25

(a) Aw.when(w, f.Ax.f(Jst(x)),g.Ax.g(snd(x))) E (--,A V --,B)::} --'(A 1\ B) (c.f. Example 1.16)

(b) Af.AX.Ay.f(X,y) E --,3(A,x.Fx)::} V(A,x.--,(Fx)) (c.f. Example 1.22)

(c) Af.Aw.split(w,(x,y).fxy) E V(A,x.--,Fx)::} --,3(A,x.Fx) (c.f. Exercise 1.11 ( a) )

36

Page 38: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(d) Aw.split(w,(X,g).Af.g(JX)) E 3(A,x.-.Fx) ~ -.V(A,x.Fx) (c.f. Exercise 1.11 (b) )

Examples (b), (c) and (d) are valid judgements in a context in which F has type A ~ U1.

(End of Example)

Note that examples 1.25(b), (c) and (d) establish "three-quarters" of DeMorgan's laws for universal and existential quantification, viz. "-.3 {:::=:? V-." and "3-, ~ -.\;f'. The final "quarter", "-.V ~ 3-.", is not generally true in constructive mathematics. Similarly, it is straighforward to establish that

which, together with example 1.25(a), forms "three-quarters" of DeMorgan's laws for con­junction and disjunction. Again, the final "quarter"

is not generally true.

Exercise 1.12 Construct proof objects for the following.

(a) -.A;\ -,B ~ -'(A V B) (b) (B ~ A) ~ (-.A ~ -.B) ( c) -,-.-,A ~ -.A (d) -'(A V B) ~ -.A;\ -.B (e) -.(A;\ -,A) (f) A ~ -,-,A (g) -'(A ~ B) ~ -,B (h) [-.-.(A ~ B) ;\ -,Bl ~ -,A

Make use of exercise 1.6(f) in the proof of (a), example 1.8 in the proof of (b) and exercise 1. 2 ( c) in the proof of (c). Note that (f) is a curried version of (e).

(End of exercise).

The empty type, 0, is an instance of an enumerated type (see section ??). It is peculiar in that it has no introduction rules. It does, however, have one elimination rule, namely that it is possible to construct an object of any type from an object of the empty type.

I[ wE 0 c> R(w) type

II q E 0

0-elimination z( q) E R( q)

(For uniformity with the enumerated-type elimination rules discussed later we should write "case(q)" instead of z(q). The absence of cases in the expression looks odd and so we prefer the abbreviated form.)

37

Page 39: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

A first example of a tautology that relies on the 0-elimination rule is the following.

Example 1.26 >.j.>.y.z(J(>.x.y)) E .(A => B) => B => A

Derivation 0.0 I[ f E (A => B) => 0 0.1.0 t> I [ 0.1.1.0 t>

0.1.1.1

0.1.2

0.1.3

0.1.4 ]I

]I

{End of example}

yEB I[ xEA t> % 0.1.0 %

yE B

11 >.x.yEA=>B

% 0.0, 0.1.2, =>-elim. % f(>.x.y) E 0

% 0.1.3, 0-elim. % z(f(>.x.y» EA

Exercise 1.13 Prove the following. (a) .(A => B) => •• A (b) A vB=> .A => B {End of exercise}

%-.(A => B)%

In presentations of the classical propositional calculus it is common to see a list of tautologies describing the algebraic properties of the connectives. It is usual also to provide one or two examples of propositional forms that are not tautologies, a single counterexample being sufficient to refute each. For example, A => A is a tautology and A => B is not. A counterexample for the latter is A = true, B = false.

In these notes, a tautology is a family of types P(A, B, C, .. . ), dependent on the type variables A, B, C, . .. assumed to be objects of Ul, such that

V(Ul' A.V(U1, B.V(Ul, C .... P(A, B, C, .. . ))))

is provable. Given such a family of types P there are now three possibilities: (a) P can be proved to be a tautology. (b) A counterexample refuting the universal validity of P can be exhibited. (c) Neither of (a) or (b) is the case.

Example 1.27 3(U1 ,A .• A)

A is not a tautology.

Derivation o 0 E U1

% example 1.24 % 1 >.x.x E --,0

% 0, 1, 3-intro % 2 (0,AX.X) E 3(U1 ,A.-.A)

{End of example}

38

Page 40: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Example 1.28

Here we use 0 to represent false and N to represent true. (Any non-empty type will do in place of N.)

Derivation

o NE Ul

1 0 E Ul

2.0 I[ lE N -::;. 0 2.1 t> 0 E N

% 2.0, 2.1, -::;.-elim % 2.2 10 E 0

II 3 V.f0 E -,(N -::;. 0)

% 0, 1, 3, 3-intro %

4 (N, (0,>'1.10)) E 3(Ul ,A.3(Ul ,B.-,(A -::;. B)))

(End of example)

Exercise 1.14 Construct counterexamples to the following propositions:

(a) A V -,B :::} -,(A V B) (b) (A:::} (B :::} C)) :::} ((A:::} B) => C) (c) ((AA B):::} (AA C)) => AA (B:::} C)

(End of exercise)

The law of the excluded middle is an example of a propositional form that can neither be proved to be a tautology, not can it be refuted by a counterexample. Specifically, by substituting 0 for B in exercise 1.5 we obtain the tautology

Quantifying over A we obtain

and applying the result that "V-, => -,3" we obtain

We interpret the last proposition as the statement that it is impossible to exhibit a type, A, for which the law of the excluded middle does not hold. (The last two steps can be proved formally within the theory. We have not done so because the mechanism for applying "V-, => -,3" has not yet been discussed. As an exercise the reader may like to prove -,3(U1, A.-,(A V

-,A) directly. Refer to exercise l.5 for hints.) The form -,-,p is of interest because it asserts that P cannot be refuted. Later (section

on universes) we prove formally that any classical tautology cannot be refuted. For the moment we just give one more particular example.

39

Page 41: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

"

Example 1.29 -'...,((A => B) V (B => A))

A classical proof of (A => B) V (B => A) when translated into type theory would take the following form. Consider three cases, A non-empty, B non-empty and both A and B empty. In the first case choose an arbitrary element x, say, of A. Then the constant function >.y.x is a proof of B => A and so inr(>.y.x) is a proof of (A => B) V (B => A). Similarly, inl(>.x.y) is a proof of (A => B) V (B => A), where y is an arbitrary element of B. Finally, if A and B are both empty the identity function proves A => B (or B => A).

This proof is not valid in type theory because it relies on the law of the excluded middle - that it is decidable whether A and/or B is nonempty. The statement that it is impossible to refute (A => B) V (B => A) is therefore the best we can hope for.

Derivation

0.0 I[ J E -,((A ~ B) v (B ~ A)) 0.1.0 I> I[ xEA 0.1.1 I> >.y.x E B ~ A 0.1.2 inr(>'y.x) E (A ~ B) v (B~ A)

% 0.0, 0.1.2 ~-elim. % 0.1.3 J(inr(>.y.x)) E 0

% 0.1.3, 0-elim % 0.1.4 z(f(inr(>.y.x))) E B

II % 0.1.0, 0.1.4, ~-intro %

0.2 >.x.z(f(inr(>.x.y))) E A ~ B % 0.2, v-intro %

0.3 inl(>.x.z(f(inr(>.x.y)))) E (A ~ B) v (B ~ A) % 0.0, 0.3, ~-elim %

0.4 J(inl(>.x.z(f(inr(>.x.y))))) E 0 II

(End of example)

Exercise 1.15

(Hard) Prove: ...,...,[(A => B V C) => ((A => B) V (A => C))]

(Easy) Explain why the classical tautology

(A => B V C) => ((A::} B) V (A => C))

is not constructively true.

(End of exercise)

40

Page 42: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

To conclude this discussion some comments on "indirect proof" in classical mathematics may be of value. Indirect proof (as I understand it, anyway) takes one of two forms. The first form is that to prove that a proposition A is true one proves that ".,A is false. In other words one proves .,.,A which, in constructive mathematics is not the same as A. This is the form used by Courant and Robbins in their proof of the infinitude of primes quoted earlier. Another form of indirect proof is used to establish a proposition like A ::} B. The strategy is to assume .,B and use it to establish .,A. This is based on the classical tautology (.,B ::} .,A) ::} A =9 B. However, this is also not a valid argument form in constructive mathematics. Indeed, it is a tautology of constructive mathematics that

(this is easy to prove) and, also,

(this is harder to prove, but see the section on universes).

Thus a proof that .,B implies .,A establishes that in a context in which A is true B cannot be refuted. Moreover the classical basis for such a proof of A ::} B can itself not be refuted in constructive mathematics, but it is not constructively valid because a proof of .,B =9 .,A does not provide a method of constructing an element of B. given an element of A.

Exercise 1.16 (See [CH, section 3.3])

Make the following definitions (where P and Q are small types)

[P] = "op P?Q = op ::} [Q]

([P] is interpreted as the classical truth of P, and? is interpreted as classical disjunction.)

Prove the following : (i) A?oA (ii) [A]?[B] =9 A? B (iii) [A?B] =9 A?B (iv) A?0 ~ [A]

(End of exercise)

The following sclose is the one promised at the beginning of this section. It terminates the scope of the assumptions A, B, C E UI .

]1

41

Page 43: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

1.5 Conclusions What we have presented so far can be viewed in two lights. In one light we have described a theory of the primitive type constructors - disjoint sum, Cartesian product, dependent product, function spaces and dependent function spaces. In this light the theorems we have established can be regarded as instances of type-coercions - mappings from· one type to another that are independent of the primitive types. In another light we have presented a constructive theory of the predicate calculus and discussed its relationship to the classical predicate calculus.

There are cogent arguments for discussing the theory only in respect of its use as a flexible and elegant type discipline. Such a discussion would use Martin-Lof's notation of "+" for disjoint sum, "x" for Cartesian product, "2::" for dependent product, "-+" for function spaces and "IT" for dependent function space. I have chosen not to do so not for any philosphical motives but simply to appeal to the reader's existing familiarity with classical reasoning. (In all honesty I have to admit that writing these notes is a - continuing - learning exercise for myself. When I began I could claim to have an adequate knowledge of classical reasoning but zero knowledge of intuitionistic reasoning. For my own peace of mind I have therefore been obliged to delve deeply into both. These notes reflect the way I have set about the task.)

This section has had several objectives, some of them more explicit than others. Among the explicit objectives have been those of introducing the basic form and structure of the rules of inference in Martin-Lof's theory and of explicating the notion of propositions -as types. Among the implicit objectives has been my intention to present a personal view on the form that an introduction to advanced programming techniques should take.

My view is that programming languages should be regarded first and foremost as algebras and programming as a calculational activity within such an algebra. (Of course I am not alone in this view but I can claim to have proposed it as long ago as 1973.) Any presentation of a programming language should therefore emphasise important algebraic properties like associativity, symmetry and distributivity. It is appropriate therefore that this first section should contain a catalogue of many such properties of the type constructors.

42

Page 44: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2 Equalities and the Equality Type Normally when we write a program it is for the purpose of computing specific values. Al­though we have claimed an identity between proof objects and programs we haven't yet shown how to compute with proof objects. This is done with the aid of equality judgements

of the form a = bE A

Such a judgement states that a and b are equal objects within the type A. Closely related to the equality judgements is the equality type. The type a A b is identi-

fied with the proposition "a and b are equal objects of type A." In essence the two different judgement forms

a = bE A

and rEa Ab

mean the same thing; moving from one form to the other is a trick that plays a central role in the theory. (I call it the Martin-LOf bottleneck!)

The fourth judgement form is A = B and asserts that A and B are equal types. Most mathematical work is done within a single type structure (for example, number

theory is about natural numbers and analysis is about real numbers). The notion that equality is typed, and that objects can be equal in one type and unequal in another, is therefore an unfamiliar one which can create surprises and also difficulties. For example, we see later (exercise 2.6) that Ax.O = Ax.x E 0 :;. 0 but it is clearly not the case that Ax.O = Ax.x EN:;. N. The difficulties caused by typed equality are therefore to do with substitution of equals for equals, such rules being less easy to apply than the rule to which most of us are used. Another disconcerting feature of the theory is the bewilderingly large number of equality rules. However the rules fall into a pattern which, once observed, makes them easier to comprehend. We begin by considering general equality rules (reflexivity, symmetry etc.) after which we consider the equality rules that are specific to individual types. The latter can be divided into two categories: computation rules which say how to compute the values of noncanonical objects in a type, and congruence rules which express the fact that equality is preserved by substitution in object expressions.

Throughout this section we assume once again that A and B are objects of the first UnIverse.

43

Page 45: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2.1 Type Formation Rule We begin our account of equalities with the type formation rule:

pEP q E P

p = q type p

=-formation

Note how the =-formation rule relies on the ability to make judgements of the form pEP. This is a significant aspect of the formal system with the implication that it is no longer possible to claim that the judgement P type means that P is a "well-formed type expression". The two judgement forms are inextricably bound together!

Our first two examples are in preparation for example 2.2; the reader may wish to scan them quickly before moving on to the next section.

Example 2.0

I[ a E A; bE B [> I[ y E B

[> (a, y) A=:'B (a, b) type

II II Derivation 0.0 0.1 0.2.0 0.2.1

I[ aEA;bEB c> (a, b) E A /\ B

I[ yE B I> (a,y) E A/\ B

0.2.2

II II

% 0.1, 0.2.1, =-form. % (a, y) = (a, b) type

AAB

(End of example)

Example 2.1

I[ a E A; bE B [> I[ x E A

[> :3(B, y.(x, y)

II II Derivation

=B(a,b)) type AA

44

,.

Page 46: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

0.0 I[ 0.1 I>

0.2.0 0.2.1.0 0.2.1.1

0.2.1.2

0.2.1

]I

a E A;b E B (a, b) EA 1\ B I[ x E A I> I[ yE B

]1

I> (x,y)EAI\B

] I

% 0.1, 0.2.1.1, =-form % (x, y) = (a, b) type

AI\B

% B type, 0.2.1, 3-form % 3(B,y.(x,y) = (a,b)) type

AI\B

(End of example)

45

Page 47: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2.2 Elementary rules Equality obeys the usual rules of reflexivity, symmetry and transitivity.

pEP reflexivity

p=pEP P=P

p=qEP P=Q symmetry

q=pEP Q=P

p= q E P P=Q q = rEP Q=R

transitivity p=rEP P=R

An object of the equality type is introduced by making equality judgements.

p=qEP =-introduction

e E P =Pq

Conversely, if we are able to construct an object of an equality type then we can also make the corresponding equality judgement.

rEp p q

=-elimination p=qEP

Note that by applying =-introduction immediately after =-elimination it is always pos­sible to replace any object r in an equality type by the object e. I.e. we have the derived rule

rEp = q p

e E P = q p.

In practice this means that e is the only object of the equality type p p q (if such an

object exists). Thus the object e has no computational significance and is there only to maintain uniformity of the judgements. Later we abandon it.

Example 2.2

)..p. split(p,(a,b).(a,(b,e))) E V(A!\ E, p.3(A, x.3(E, y.(x, y) A~B p)))

From a theoretical viewpoint this example is truly remarkable. It asserts that every element of a conjunction is a pair - in other formal systems such a judgement would be implicit or stated as an axiom. From a practical viewpoint this and similar properties are

46

Page 48: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

I,

indispensable since we use them often to simplify complex objects. Thus the following derivation is well worthwhile studying.

Derivation

0.0 I[ pEA A B 0.1.0 t> I[ a E A; bE B

t> % 0.1.0, A-intro % 0.1.1 (a, b) E A A B

% 0.1.1, refi % 0.1.2 (a, b) = (a, b)

AI\B

0.1.3

0.1.4

0.1.5

]I

% 0.1.2, =-intro % e E (a, b) = (a, b)

AI\B

% example 2.0, 0.1.0, 0.1.3, 3-intro % (b, e) E 3(B, y.(a, y) = (a, b))

AI\B

% example 2.1, 0.1.0, 0.1.4, 3-intro % (a, (b, e)) E 3(A, x.3(B, y.(x, y) = (a, b)))

AI\B

% 0.0, 0.1, A-elim % 0.1 split(p, (a, b).(a, (b, e))) E 3(A, x.3(B, y.{x, y) A~B p))

11

The steps worth studying are the final three. Steps 0.1.4 and 10 .. 5 are the first ~eal examples we have been able to give of the use of families of types. Specifically, example 2.0 states that (a, y) =B (a, b) is to be regarded as a family of types where y ranges over the type

AA B. A particular instance of this family is the type (a, b) = (a, b) about which a judgement

AAB is made in step 0.1.3. Thus 0.1.4 follows by the 3-introduction rule. Similarly, example 2.1 states that 3(B,y.(x,y) A~B (a,.b)) is to be regarded asa familyoftypes where x ranges over

the type A. A particular instance of this family is the type 3(B, y.(a, y) A~B (a, b)) about

which a judgement has been made in step 0.1.4. Thus 0.1.5 follows by the 3-introduction rule. Step 0.1 illustrates the use of substitution in the type expression when using A-elimination - again something we have not illustrated earlier.

(End of example)

Exercise 2.0 Prove: V(A V B,d.3(A,x.inl x =B d) V 3(B,y.inr y =B d)) AV AV

Formulate a property similar to that in example 2.2 relating to existential quantification. Establish the property.

(End of exercise)

47

Page 49: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2.3 Substitutivity Properties Two sets of rules express substitutivity of equals for equals. substitutivity of equal objects for equal objects in a type.

The first set expresses the

I[ x E P I[ x E P [> r(x) = s(x) E R(x) [> Q(x) = R(x) 11 11 p=qEP p=qEP

r (p) = s ( q) E R(p) Q (p) = R( q )

Example 2.3 V(A, a, a'.V(A => B, f.(a = a') => (fa = fa'))) A B

Derivation 0.0 1 [

0.1.0 l>

0.1.1 0.1.2.0

0.1.2.1

0.1.3

0.1.4

] 1

a, a' E A; f E A ~ B I[ rEa = a'

A

l> % 0.1.0, =-elim %

11

a = a' EA I[ x E A l> % 0.0,0.1.2.0, ~-elim,refi %

fx = fx E B ]1

% 0.1.1,0.1.2,subst % fa = fa' E B

% 0.1.3, =-intro % e E fa = fa'

B

End of example

Exercise 2.1 Prove the following :

substitution

(a)

(b)

(c)

(d)

V(A, a, a'.V(A => B, J,g.(a A a') => (f A::B g) => (fa B ga')))

V(A => B, f,g·(f A::B g) => ()..x.fx A~B )..x.gx))

V(A, a,a'.V(B, b,b'.(a Aa')=>(b Ab')=> ((a,b) A=:B(a',b')))

V(A, a, a'.(a A a') => (inl a A~B inl a'))

End of exercise

The second set of rules expresses the substitutivity of equal types.

P=Q pEP

pEQ

P=Q p=qEP

p=qEQ

Example 2.4 This example has been removed.

48

type equality

Page 50: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

.,

Exercise 2.2 This exercise has been removed.

Example 2.5 (Arguments for absurdity)

V(U1 , A, B, C.V(A, x.V(B,y.0 =} zx C zy)))

The constant z introduced by the 0-elimination rule has a single argument but this argument has no significance and may be replaced by any object of any type.

Derivation % Ul-form, Ul-elim, refi %

0.0 1 [ X E Ul 0.1 C> X=X

1I 1.0 1 [ A,B,CE Ul 1.1.0 C> 1 [ x E A;y E B 1.1.1.0 C> I[ aE0

C> % 0 E Ul, 1.0, =-form % 1.1.1.1 0 = A type

u, % 1.1.1.0, 1.1.1.1, 0-elim %

1.1.1.2 za E 0 = A u, % 1.1.1.2, =-elim %

1.1.1.3 0= A E Ul % 0, 1.1.1.3, subst %

1.1.1.4 0=A % 1.1.0, 1.1.1.4, type equality %

1.1.1.5 xE0 % 1.1.1.5, 1.0, Ul-elim, 0-elim %

1.1.1.6 zx E C % similarly %

1.1.1.7 zy E C % 1.1.1.6, 1.1.1.7, ~-form %

1.1.1.8 zx C zy type

% 1.1.1.0, 1.1.1.8, 0-elim % 1.1.1.9 za E zx C zy

1I II

II Notes ( a) The step from 1.1.1.3 to 1.1.1.4 can be made directly using an inference rule to be

presented in section 3. Our use of step 0 was a simple trick to avoid introducing the rule at this stage.

(b) I do not like the use of "similarly" in step 1.1.1.7. However, the substitution rule that I have in mind does not appear to be included in Martin-Lof's rules. This mayor may not be significant.

49

Page 51: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(c) In spite of its apparent uselessness, this example is important to us when we consider subset types. The property was pointed out to me (in a slightly different guise) by Stuart Anderson.

(End of example)

Exercise 2.3 Show that >'x.x E 0 => A (End of exercise)

50

Page 52: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2.4 Congruence and Extensionality Properties A number of rules in the theory express congruence properties of equality with respect to the various operators. Some of these rules, for instance the congruence of pairing, can be estab­lished using the simple properties of substitution already stated. Where an operator involves abstraction (e.g. A and when), however, the properties we require cannot be established using simple substitution, and they make significant use of the rules in this section.

I[ x E P Do p(x) = q(x) E Q JI

A-congruence AX.p(X) = AX.q(X) E P =? Q

Exercise 2.4 Show that ...\x.x = AX.ZX E 0 =? A (End of exercise)

The rule known as "eta-reduction" in the Lambda calculus is an ad-hoc addition to the system (i.e. it does not fall into the pattern of the other rules). It and A-congruence guarantee extensionality of functions (see example 2.6).

fEP=?Q

AX.f x = f E P =? Q (where x does not occur free in 1)

ry-reduction

(Note that an immediate consequence of this rule is the property V(A =? B, f.f =B Ax.fX). A::;.-

This is the closure property of implication akin to the closure properties stated in example 2.2 and exercise 2.0. The fact that it is not derivable except by ry-reduction emphasises the ad-hoc nature of the rule. Martin-Lof has now eliminated the anomaly by "the adoption of a systematic higher level notation" [SaJ. (We will discuss the new notation and the revised rules for implication and universal quantification later.)

Example 2.6 (Extensionality of functions)

51

Page 53: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 1 [ f,g EA=> B 0.1.0 t> I[ hE 'v'(A, a.fa = ga)

B

0.1.1.0 t> I[ a E A t> % 0.1.0, 0.1.1.0, 'v'-elim %

0.1.1.1 ha E fa = ga B

% 0.1.1.1, =-elim % 0.1.1.2 fa = ga E B

]1 % 0.1.1, A-congr %

0.1.2 Aa.fa = Aa.ga EA=> B % 0.0, 7]-red %

0.1.3 Aa.fa = f EA=> B

% 0.0, 7]-red % 0.1.4 Aa.ga = 9 EA=> B

% 0.1.2, 0.1.3, 0.1.4, sym, trans % 0.1.5 f=gEA=>B

]I ]1

(End of Example)

Exercise 2.5 (The most elementary instance of extensionality) Show that V(0 =* A, J.f 0;A AX.Z(X))

(End of exercise)

Take careful note of the premise in the 7]-reduction rule. It is not possible to derive -for very good reasons - the judgements z E 0 =* A or inl E A =* A V B within the theory. Thus, for example, the consequent in exercise 2.5 cannot be simplified to f 0;A z .

. Example 2.8 (Proof objects of negations)

V(-.A,J.f = AX.X) ...,A

The identity function is the unique proof object of -,A, if such an object exists. Thus there is no computational content in any proof object of -,A.

52

Page 54: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 I [ f E...,A 0.1.0 [> I[ xEA

[> % 0.0, 0.1.0, ::}-elim % 0.1.1 fx E 0

% 0.1.1, 0-elim % 0.1.2 z(fx) E fx =X

0

% 0.1.2, =-elim % 0.1.3 Ix = x E 0

] I % 0.1, ,\ -congr %

0.2 '\x.fx = '\x.x E ...,A

% 0.0, 1J-red % 0.3 '\x·fx = f E ...,A

% 0.2, 0.3, sym, trans % 0.4 f = AX.X E...,A

]I

Several steps have been omitted in the deduction of 0.1.2. We have to show that fx 0' x

is a type which, in turn, requires a proof of x E 0. The latter judgement can be derived as in example 2.5.

(End of example)

Exercise 2.6

(End of exercise)

Show that AX.O = AX.X E 0 =} 0

The congruence rules for function application, pairing and injection add nothing new to the system. Following Martin-Lof we include them for uniformity.

p=qEP r=sEP=}Q

congruence of function application rp = sq E Q

p = p' E P q = q' E Q

(p, q) = (p', q') E P /\ Q

p=qEP

inl p = inl q E P V Q

p = q E Q

inr p = inr q E P V Q

O-congruence

inl-congruence

Inr-congruence

There are similar rules for universal quantification and existential quantification.

53

Page 55: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Exercise 2.7 Show that V(A, a, b.-.(inl a A~B inl b) => -.(a A b)).

Complete the following proposition and prove it.

V(A, a,a'.V(B, b,b'.-.((a,b} =B (a',b'}) =>?71)) AA

(End of exercise)

The abstractions when and split also preserve equality; like A-congruence the following rules appear to be independent of other rules.

***

I[ x E P A Q [> R(x) type

II p=qEPAQ I[ y E P; z E Q [> r(y,z) = s(y,z) E R((y,z})

II

split(p, (y, z).r(y, z)) = split(q, (y, z).s(y, z)) E R(p)

I[ x E P V Q [> R(x) type

II p=qEPVQ I[ yE P [> r(y) = r' (y) E R(inl y)

II I[ z E Q [> s(z) = s'(z) E R(inr z)

II

when(p,y.r(y),z.s(z)) = when(q,y.r'(y),z.s'(z)) E R(p)

split-congruence

when-congruence

Examples and exercises exploiting the above rules appear in the next section. Any suggestions for further examples that can be included at this point in the text would be welcome.

54

Page 56: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2.5 Computation Rules Martin-Lof calls the rules in this section the "equality rules". However, their function is to say how to compute the value of non-canonical objects; we therefore prefer to refer to them as "computation rules".

We recall that the canonical objects of a type are created by the introduction rules, and non-canonical objects are created by the elimination rules. Thus t~e non-canonical objects associated with implication are function applications, those associated with disjunctions are when expressions etc. It is an important attribute of the theory that it suffices to specify how to compute the value of a non-canonical object when applied to a canonical object of the associated type. Thus, it suffices to define how to evaluate the application of A-abstraction (a canonical object of an implication-type) to a given argument; it is not necessary to say how to evaluate the application of a non-canonical functional expression to a given argument. The closure properties discussed in example 2.2 and exercise 2.0 are thus both vital to our understanding of the theory and to its practical application.

In the jargon of computing science, expression evaluation is "lazy"', i.e.; an expression is fully evaluated if its principal or outermost connective is a canonical-object constructor. Thus, for example, in section 1.3(f) we saw lots of expressions involving the (non-canonical) constructor z. This does not give rise to any problems even though the latter may be regarded as a non-terminating computation. However, were evaluation non-lazy, say call-by-value, then many of the objects we construct would be undefined (in the sense of non-terminating). __

(a) Function application

The computation rule for function application IS the familiar rule of fi-reduction in the Lambda calculus.

I[ x E P c> q(x) E Q JI pEP

:::}-compu tation (AX.q(X))p = q(p) E Q

Example 2.8 11 = I

The examples and exercises that follow (up to and including exercise 2.10) are all well­known properties of the combinators, S, J(, I and B [CF,St, TuJ. In a typed system the results are slightly more complex, but also a little clearer. In this example we prove that hIo = 10 where h = AX.X E (A:::} A) :::} (A :::} A) and 10 = Ay.y EA:::} A. Since this is a very elementary example we also use it to illustrate our technique for introducing definitions.

55

Page 57: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation 0.0 0.1.0 0.1.1.0 0.1.1.1.0 0.1.1.1.1.0 0.1.1.1.1.1

0.1.1.1.2

0.1.1.1.3

I[ It E (A ~ A) ~ (A ~ A) c> I [ rEIl = AX.X

]I

c> I[ 10 E A ~ A

]I

c> I [ s E 10 = Ay·y

]I

c> I[ x E A ~ A

]I

c> xEA~A

]I % 0.1.1.1.1, 0.1.1.0, ~-comp %

(Ax.x)Io = 10 E A ~ A % 0.1.0, 0.1.1.1.2, exercise 2.1(a) %

It 10 = 10 E A ~ A

Two steps are used to introduce theabh'reviation h for AX.X. First we say what type h has (step 0.0) and then we assume (step 0.1.0) that we have·an'object of the equality type h = AX.X. (The type (A =? A) =? (A =? A) should be made explicit in this second step but that would be overkill.) The same two steps have been used to introduce 10. Note that the definition of 10 is never used.

(End of example)

Example 2.9 BI= I

In this case the property we prove is Blo = h where B = AX.Ay.AZ.X(YZ) E (A =? A) =?

(A =? A) =? A =? A, and 10 and h are as above.

56

Page 58: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 1 [ B = )..x.)..y.)..z.x(yz) E (A:::} A) :::} (A:::} A) :::} A:::} A 0.1 10 = )..x.x EA:::} A;ll = )..y.y E (A:::} A) :::} A :::} A 0.2.0 I> 1 [ xEA:::}A

I> % 0.1.0, :::}-intro, :::}-elim % 0.2.1 )..y.AZ.X(YZ) E (A:::} A) :::} A:::} A

] 1

% 0.0, 0.1, :::}-comp % 0.3 (h.)..y.)..z.x(yz)) 10 = Ay.Az.lo(Yz) E (A:::} A) :::} A :::} A

% 0.0,0.2, exercise 2.1(a) % 0.4 Blo = )..y.)..z.Io(Yz) E (A:::} A) :::} A:::} A 0.5.0 I[ yEA:::}A 0.5.1.0 I> I[ zEA

I> % 0.4.0, 0.4.1.0, :::}-elim % 0.5.1.1 yz EA 0.5.1.2.0 I[ xEA 0.5.1.2.1 I> xEA

]I % 0.4.1.1, 0.4.1.2, :::}-comp %

0.5.1.3 (.Ax.x)(yz) = yz EA % 0.0, 0.4.1.3, exercise 2.1(a) %

0.5.1.4 Io(yz) = yz EA • ]I

% 0.4.1, )..-congr % 0.5.2 )..z.Io(Yz) = )..z.yz EA

% 0.4.0, 7J-red % 0.5.3 )..z.yz = yEA:::} A

% 0.4.2, 0.4.3, trans % 0.5.4 )..z.Io(yz) = yEA:::} A

II % 0.4, )..-congr %

0.6 )..y.)..z.Io(yz) = .Ay.y E (A:::} A) :::} A :::} A % 0.3, 0.5, 0.0, trans %

0.7 Blo = 11 E (A :::} A) :::} A:::} A

II Note that step 0 abbreviates the method used in example 2.8 for the introduction of abbre­viations.

(End of example)

Exercise 2.8

where and

Establish the following.

S(J< 10) = h E (A =? A) =? A =? A S = Af.Ag.AX.fX(gX) E (A =? A =? A) =? ((A =? A) =? A =? A) f{ = AX.Ay.X E (A =? A)=? (A =? A =? A)

(End of exercise)

Exercise 2.9 Assuming that S == Af.Ag.AX.fX(gX) , f{ == AX.Ay.X, B = AX.Ay.AZ.X(YZ) and I == AX.X, what type assignments (to each occurrence of each variable) are sufficient to make sense of the following equalities :

57

Page 59: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

(a) (b)

S(KS) = B SKK=]

(End of exercise)

The rule for V-computation is the obvious extension of the ::;.-computation rule to de-pendent types.

I[ x E P t> q(x) E Q(x)

II pEP

V-computation (>.x.q(x))p = q(p) E Q(p)

Exercise 2.10 (For the very assiduous) Establish the following :

I[ FE A::;. U1 ; G E V(A,a.Fa::;. U1)

t> I[ S = >.f.>.g.fx(gx) E V(A, x'v(Fx, y.Gxy)) ::;. V(V(A, x.Fx), h.V(A, x.Gx(hx ))) t> I[ Kl = >.x.>.y.x E V(A, x.V(V(Fx, z.A),y.A))

t> I[ K2 = >.x.>.y.x E V(A, x.V(Fx, y.A)) t> SK1K2 = >'x.x E V(A,x.A)

II II

II II (End of exercise)

(b) Splitting Pairs

The non-canonical objects associated with conjunction and existential quantification are objects of the form split(p, (x, y).q(x, y)). Viewed operationally such a construct splits p into its two components; these are then bound to x and y in the computation of q. The formal statement of the computation rule is very straightforward because we need only say what it means to split a pair.

I[ x E P /\ Q t> R(x) type

II pEP q E Q I[ yEP;zEQ t> rER((y,z))

II

split((p,q),(y,z).r(y,z)) = r(p,q) E R((p,q))

58

/\-computation

Page 60: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Example 2.10

I[ pEA AB [> split(p, (a, b).(a, b)) = pEA A B ] 1

Derivation 0.0 I[ 0.1.0 C>

0.1.1.0 0.1.1.1

0.1.2

0.1.3

pEA/\B I[ a'EA;b'EB C> I[ aEA;bEB

II

c> (a,b) E A/\ B II

% 0.1.0, /\-intro, 0.1.1, /\-comp % split«(a', b'), (a, b).(a, b)) = (a', b') EA /\ B

% 0.1.2, =-intro, =-elim % e E split«(a', b'), (a, b).(a, b)) = (a', b')

AAB

% 0.0, 0.1, /\-elim % 0.2 e E split(p, (a, b).(a, b}) = P

AAB

II (End of example)

Exercise 2.11 (Cancellation)

Establish the following :

(a) V(A, a.V(A, a'.V(B, b.V(B, b'.[( (a, b) A';..B (a', b')) => (a A a')]))))

(a) V(A, a.V(A, a'.V(B, b.V(B, b'.[-,((a, b) A';..B (a', b')) => -,(a A a' A b Bb')]))))

Hint: See exercise 2.7 for one half of this equivalence. For the other half make use of example 2.10, split-congruence and split-computation.

(End of exercise)

The 3-computation rule generalises the A-computation rule to dependent types.

I[ w E 3(P, x.Q(x)) [> R(w) type

11 pEP q E Q(p) I[ YEP;zEQ(y) [> s(y,Z)ER((y,z))

11

split((p,q), (y,z).s(y,z)) = s(p,q) E R((p,q)) Example 2.11

I[ FE A=> U1

[> >.p.split(p, (a', b').b') E V(3(A, a.Fa),p.F(split(p, (a, b).a)))

11

59

3-compu tation

Page 61: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

The second component of a pair pin 3(A, a.Fa) is a proof that the first component has the property F.

Derivation 0.0 I[ FEA::;,-U1

0.1.0 t> I[ pE 3(A, a.Fa) 0.1.1.0 t> I[ a' EA; b' E Fa' 0.1.1.1.0 t> I[ a E A; bE Fa

0.1.1.1.1

0.1.1.2

0.1.1.3

0.1.2

II 1I

(End of example)

II

t> % 0.1.1.1.0 % a E A

II % 0.1.1.0, 3-intro, 0.1.1.1, 3-comp %

split«(a', b'), (a, b).a) = a' E A % 0.1.1.0, 0.1.1.2 refi, subst, type eq %

b' E F(split«(a', b'), (a, b).a))

% 0.1.0, 0.1.1, 3-elim % split(p, (a', b').b') E F(spllt(p, (a, b ).a))

Example 2.12 (A conditional implication)

I[ FE A::} U1

t> V(A,a.V(Fa,b.V(A,a'.V(Fa',b'.((a,b} 3( =F) (a',b'})::} (b = b'))))) A,x. x Fa

JI

As the reader will have realised, we have been omitting type judgements for some time. We give the full details of this example because it is the first example of a conditional implication, and hence the first example that makes full use of the ::}-formation rule in section 1.2( a).

60

Page 62: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 0:1.0

0.1.1

0.1.2

0.1.3

0.1.4.0

0.1.4.1

0.1.4.2

0.1.4.3

0.1.5

0.1.6.0

0.1.6.1 0.1.6.2.0

0.1.6.2.1

0.1.6.3

0.1.6.4

0.1.6.5

0.1.6.6

0.1.6.7

0.1.6.8

0.1.7

J[ I>

11

FE A =:> Ul I[ a E A;b E Fa;a' E A;b' E Fa' I> % 0.1.0, 3-intro %

]I

(a,b) E 3(A,x.Fx) % 0.1.0, 3-intro %

(aI, b/) E 3(A, x.Fx) % 0.1.1, 0.1.2, =-form %

(a,b) = (a',b/) type 3(A • .,.F.,)

I[ rE(a,b) = (a',b/) 3(A • .,.F.,)

I> % 0.1.4.0, exercise 2.8 %

11

a = a' EA % 0.0, 0.1.4.1, =:>-elim, Ul-elim, refi, 0.1.0, subst, type eq %

b' E Fa % 0.1.0,0.1.4.2, =-form %

b = b' type Fa

% 0.1.3,0.1.4, =}-form % ((a, b) = (a', b/) =:> (b = I b') type

3(A • .,.F.,) Fa

I[ rE (a, b) = (a', b/) 3(A • .,.F.,)

I> % 0.1.6.0, =-elim %

11

(a, b) = (a', b/) E 3(A, x.Fx) I[ cEA;dEFc I> % 0.1.6.2.0, example 2.11 %

dE F(split((c, d), (c', dl).C'»

11 % 0.1.6.1, 0.1.6.2, split-congr %

split( (a, b), (c, d).d) = split( (a', b/), (c, d).d) E F(split( (a, b), (c', d').c/» % 0.1.1,0.1.6.2, 3-comp %

split( (a, b), (c, d).d) = b E F(split( (a, b), (c', d' ) .c/»

% 0.1.2,0.1.6.2, 3-comp % split( (a', b/), (c, d).d) = b' E F(split( (a, b), (c', d').C/»

% similarly % split((a, b), (c', d').c/) = a E A

% 0.1.6.3, 0.1.6.4, 0.1.6.5, 0.1.6.6, subst, type eq, trans, sym % b = b' E Fa

% 0.1.6.7, =-intro % e E b = b' Fa

% 0.1.5,0.1.6, =:>-intro % ).r.e E ((a,b) = (a/,b' ) =:> (b = b')

3(A • .,.F.,) Fa

The most interesting aspect of this derivation is step 0.1.4. It is impossible to make the judgement that b F= b' is a type except in a context in which a = a' is provable. But to

a A

prove the latter given the assumption that (a, b) = (a', b') we are obliged to make use of

61

Page 63: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

the computation rules. Hence our earlier remark about each of the judgement forms being inextricably bound together.

(End of example)

Exercise 2.12 Prove the following :

I[ FE A => Ul t> V(3(A, a.Fa),p.snd p F(f~t p) snd p)

JI where fst p denotes split(p, (a, b).a) and snd p denotes split(p, (a, b).b).

This curious exercise (which may appear trivial at first sight) illustrates the way that type membership is expressed in the theory. A paraphrase of the theorem is that snd p has type F(fst p) whenever p has type 3(A, a.Fa).

(End of exercise)

At last we come to the first and only example in Martin-Lof's celebrated paper [M-LJ.

Example 2.13 (Axiom of choice)

I[ FE A=> Uli G E V(A, x.Fx => U1)

t> )..f.()..x.fst(fx), )..x.snd(fx)) E V(A, x.3(Fx, y.Gxy)) => 3(V(A, x.Fx), h.V(A, x.Gx(hx)))

JI (Cf., also, exercise 2. 2(b).)

The two assumptions state that Fa is a (small) type whenever a is in A and Gab is a (small) type whenever a is in A and b is in Fa. In such a context the axiom of choice is valid. That is, if for all x in A it is known that there is a y in Fx such that Gxy, then there is a choice function h that given an object x of A constructs such an object. (Omitting types in the quantifiers the axiom reads: V(x.3(y.Gxy)) => 3(h.V(x.Gx(hx))).)

62

Page 64: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 J( 0.1.0 t>

0.1.1.0

0.1.1.1

0.1.1.2

0.1.2 0.1.3.0 0.1.3.1.0

0.1.3.1.1

0.1.3.1.2

0.1.3.1.3

0.1.3.2

0.1.4

0.1.5

0.1.6

II

FE A => U1 ; G E V(A, x.Fx => U1 )

J( f E V(A, x.3(Fx, y.Gxy)) t> I[ x E A

II

I> % 0.1.0, 0.1.1.0, V-elim %

II

Ix E 3(Fx, y.Gxy) % 0.1.1.1, 3-elim %

fst(fx) E Fx

% 0.1.1, V-intro % >'x.lst(fx) E V(A, x.Fx) I[ h = >.x·fst(fx) E V(A, x.Fx) t> I[ xEA

II

I> % 0.1.1,0.1.3.1.0, V-comp, subst %

II

hx = fst(fx) E Fx % 0.1.0,0.1.3.1.0, V-elim %

Ix E 3(Fx, y.Gxy) % 0.0, 0.1.3.1.1, 0.1.3.1.2, example 2.11, subst %

snd(fx) E Gx(hx)

% 0.1.3.1, V-intro % >..x.snd(fx) E V(A, x.Gx(hx))

% 0.1.3, V-intro(twice) % >.h.>..r.>.x.snd(fx) E V(V(A, x .Fx), h.V(h = >..x.split(fx, (y, z)y), r.V(A, x.Gx(hx))))

V(A,:t".F:t")

% 0.1.2, 0.1.4, refi, V-comp % >.x.snd(fx) E V(A, x.Gx((>.x.snd(fx))x))

% 0.1.2,0.1.5, 3-intro % (>.x./st(fx) , >.x.snd(fx)) E 3(V(A, x.Fx), h.V(A, x.Gx(hx)))

Note (to myself) the introduction of the abbreviation h for the choice function >.x.fst(Jx). Such techniques should be encouraged in formal derivations but once again I find that the substitution rule in Martin-Lof's theory is not powerful enough for my purposes - see steps 0.1.4, 0.1.5.

(End of example)

(c) V -computation

There are two computation rules for when objects, one for each sort of canonical object.

63

Page 65: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

I[ xEPVQ [> R(x) type

11 I[ yE P [> r E R(inl y) JI I[ z E Q [> S E R(inr z)

11 pEP

when(inl p, y.r(y), z.s(z)) = r(p) E R(inl p)

I[ x E P V Q [> R(x) type

11 I[ yE P [> rER(inly)

11 I[ z E Q [> S E R( inr z) 11 q E Q

when(inr q, y.r(y), z.s(z)) = s(q) E R(inr q)

v -computation

V -computation

The operational understanding of when is that when(t,y.r(y),z.s(z)) picks out either r(y) or s (z) depending on the form taken by t. If it has the form inl p then r is evaluated with the parameter y bound to p. On the other hand if it has the form inr q then s is evaluated with the parameter z bound to q.

Example 2.14

V(A V E, d.when(d, a.inl a, b.inr b) A~B d)

64

Page 66: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Derivation

0.0 0.1.0 0.1.1.0

0.1.1.1

0.1.2.0

0.1.2.1

I[ dE A v B I> I[ a' EA

I> I[ aEA I> % 0.1.1.0, v-intro %

inlaEAVB ]I I[ bE B I> % 0.1.2.0, v-intro %

inrbEAvB ]I

0.1.3 % 0.1.0, V-intro, 0.1.1,0.1.2, V-cemp, =-intro %

e E when(inl a',a.inl a,b.inr b) = inl a' AvB

] 1

% similarly % 0.2.0 I[ b' E B 0.2.1 I> e E when(inr b', a.inl a, b.inr b) = inr b'

AvB

]1

0.3 % 0.0, 0.1, 0.2, -comp, =-intro, =-elim %

e E when(d, a.inl a, b.inr b) = d . AvB

]I

Strictly it is necessary to prove that when(x, a.inl a, b.inr b) A=:JB x is a family of types

indexed by x E A vB. This step has been omitted.

(End of example)

Exercise 2.13 ( Cancellation)

Establish the following :

(a) V(A, aV(A, a'.(inl a A=:JB inl a') {:=:} (a A a')))

(b) V(A,a.V(A,a' .• (inl a A=:JB inl a') {:=:} .(a A a')))

(End of exercise)

At the end of section 1 I argued the case for a detailed study of algebraic properties. It seems appropriate to remark at this point that we are still unable to establish the judgement • (inl a =B inr b) whenever a E A and b E B. Its derivation must wait until the universes

AV have been introduced in section 3.

11

65

Page 67: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

2.6 In Retrospect By now I expect that some readers will have been tempted to rush past the seemingly endless series of "trivial" examples and exercises. However, in spite of their simplicity, many are extremely important and worthy of deep reflection. I propose, therefore, to briefly review those that I find especially significant.

Example 2.2 and exercise 2.0 describe closure properties of conjunction and disjunction. (Roughly speaking, every conjunct is a pair and every disjunct is of the form inl a or inl b for some a or b.) The remarkable aspect of these examples is their use of the notion of a family of types. The reader will also have noted a pattern in their derivation which reflects a deeper pattern in the construction of the rules. This aspect of the theory is yet another that we postpone for later discussion.

The notion of a conditional implication was illustrated by example 2.12. This example is important because it shows that conditional expressions can be discussed without introducing a notion of undefined values. (Commonly, i.n computing an~ logic texts, the "undefined" value is a perfectly well-defined value that is confusingly given the name "undefined".) The example may well seem to be at variance with some of the properties discussed in section 1, for example the property (see exercise 1.2( a))

I[ A,B,C E U1

t> [A => (B => C)] ~ [B => (A => C)] ]1

Is it a corollary of the above, for instance, that

I[ FE A=> U1;a,a' E A;b E Fa;b' E Fa' t> [(a = a') => (b = b') => ((a,b) ::l = (a',b'))]

A Fa ~(A,x.Fx)

=> [(b = b') => (a = a') => ((a b) = (a' b'))] Fa A '3(A,x.Fx)'

]1

The answer is no, because the context in exercise 1.2( a) specifies A, Band C to be variables in U1 , and there can thus be no dependance among them. Since we cannot establish the judgement b = b' E U1 , exercise 1.2( a) is inapplicable.

Fa

Example 2.13 is Martin-Lof's favourite. But I have chosen to be much more formal in my presentation - not only in respect of providing much greater detail than Martin-Lof. In particular, I have proved the axiom of choice in a context in which A E U1 , FE A=? U1 and G E V(A, x.Fx => U1 ). In his presentation, Martin-Lof makes the following assumptions

A type F(x) type [x E A] G(x,y) type [x E A;y E F(x)]

But there is no mechanism within his formal system to make such assumptions! This points to a deficiency in his theory about which he has not been completely frank, but which we will return to in the section on universes.

66

Page 68: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

Several examples, all involving the empty type, have been concerned with the (lack of) computational content in proof objects, and we have alluded to the subset type to be introduced later. Originally, I had intended to introduce the subset type at this point in the dicussion. However, I am currently of the opinion that the intrusion of proof objects with no computational content is a serious flaw in the theory that is only compensated to a limited extent by the subset type. I am therefore delaying the latter's introduction until I have better understood the problems myself.

67

Page 69: ONE DAY SEMINAR Professor Roland Backhouse...Functional Programming Logic Programming Program Verification The first of these, the introduction of type declarations (enumerated types,

References [Ba] R.C. Backhouse "Overcoming the mismatch between programs and proofs".

Proceedings of workshop on Programming Logic, Marstrand, June 1-4 1987, Chalmers Univ. of Technology, Dept. of Computer Sciences.

[Be] M.J. Beeson Foundations of Constructive Mathematics Springer-Veriag, Berlin (1985).

[BI] E. Bishop Foundations of Constructive Analysis McGraw-Hill, New York (1967).

[BL] R. Burstall and B. Lampson "A kernel language for abstract data types and modules" In Semantics of Data Types Eds. G. Kahn, D.B. MacQueen and G. Plotkin, Lecture Note~ in Computer Science 173, 1-50 (1984).

[CH] Th. Coquand and G. Huet "Constructions: A higher order proof system for mechanizing mathematics" EUROCAL 85 (April 85) Linz, Austria.

[CR] R. Courant and H. Robbins What is mathematics'? Oxford Univ. Press, London (1941).

[Ge] G. Gentzen "Investigations into logical deduction" In The Collected Papers of Gerhard Gentzen, pp. 68-213, M.E. Szabo (Ed.), North-Holland, Amsterdam (1969).

[GMW] M. Gordon, R. Milner and C. Wadsworth Edinburgh LCF Springer-Verlag Lecture Notes in Computer Science, 78, (1979).

[Ho] C.A.R. Hoare "Notes on data structuring" In Structured Programming, O.-J. Dahl, E.W. Dijkstra and C.A.R. Hoare (Eds.), Academic Press (1972).

[J a] M.A. J ackson Principles of Program Design Academic Press (1975).

[M-L1] P. Martin-Lof "Constructive mathematics and computer programming" Proc. 6th Int. Congress for Logic, Methodology and Philosophy of Science (Eds. L.J. Cohen, J. Los, H. Pfeiffer and K.-P. Podewski) pp. 153-175, North-Holland Pub!. Co. (1982).

[M-L2] P. Martin-Lof "Intuitionistic Type Theory" Notes by Giovanni Sambin of a series of lectures given in Padova, Juni 1980.

[Mi1] R. Milner "A theory of type polymorphism in programming" J. Comp. Syst. Scs. 17, pp. 348-375 (1977).

[Mi2] R. Milner "The standard ML core language" Polymorphism Il, 2 (October 1985).

[NPS] B. Nordstrom, K. Petersson and J. Smith "An introduction to Martin-Lof's Type Theory" Chalmers Inst. of Technology, Dept. of Computer Sciences, Midsummer 1986.

[Pe] K. Petersson "A programming system for type theory" Memo 21, Programming Methodology Group, Chalmers Inst. of Technology, Goteborg, Sweden (1982).

[PRL] The PRL Staff "Implementing Mathematics with the NuPRL Proof Development System" Prentice-Hall Inc., Englewood Cliffs, New Jersey (1986)

[St] J. Stoy Denotational Semantics The MIT Press, Cambride, Mass. (1977).

[Tu] D. Turner "A new implementation technique for applicative languages" Software-Practice and Experience, 9,31-49 (1979).

1