• No results found

Now we put these rules to some use in a series of examples. For the first example we assume

θ≡df ∀x.(P(x)⇒Q(x))

∃x.P(x) and try to prove that

1.2. PREDICATE LOGIC 25 Informally the inference is clear, but what do we do in our system? We have a universal assumption, θ, and the rule of universal elimination tells us that we can use any instance

P(x)⇒P(x)

ofθin our proof. If we adopt abackwards reading of the rule of existential elimination, then we see how to use an existential assumption.

To use an existential assumption ∃x.P(x) , use the instance

P(x) and finally discharge this using the rule (∃E). Proceeding thus we have

P(x) ∀x.(P(x)⇒Q(x)) (P(x)⇒Q(x)) (∀E)

Q(x) (⇒E)

From this we can infer∃x.Q(x) (even thoughxis free in one of the assump- tions — there are no restrictions on the rule (∃I)), and finally by existential elimination we have: ∃x.P(x) [P(x)]1 ∀x.(P(x)⇒Q(x)) (P(x)⇒Q(x)) (∀E) Q(x) (⇒E) ∃x.Q(x) (∃I) ∃x.Q(x) (∃E)1 For our second example, suppose we make the assumption that every object is either an apple or a banana:

∀x.(A(x)∨B(x))

and that both apples and bananas are tasty:

∀x.(A(x)⇒T(x))

∀x.(B(x)⇒T(x))

We will show that everything is tasty,∀x.T(x).

Applying the universal elimination rule three times we have (A(y)∨B(y))

(A(y)⇒T(y)) (B(y)⇒T(y))

and then we can infer T(y) on the basis of the second of these and the assumptionA(y), using (⇒E).

A(y) ∀x.(A(x)⇒T(x)) (A(y)⇒T(y)) (∀E)

T(y) (⇒E)

We can similarly infer T(y) from B(y) and the universal statement, and are then in a position to apply (∨E). (In the diagram which follows the hypotheses of the central proof are listed vertically.)

∀x.(A(x)∨B(x)) (A(y)∨B(y)) (∀E) [A(y)]1 ∀x.(A(x)⇒T(x)) .. . T(y) [B(y)]1 . . . .. . T(y) T(y) (∨E)1

∀introduction is then applied, giving ..

.

∀x.T(x)(∀I)

Our final example concerns the proof of

∃y.∀x.A(x, y)⇒ ∀x.∃y.A(x, y)

The reader might like to refer back to the discussion on page 18 above. Remembering the rule of implication introduction, it is sufficient to prove

∀x.∃y.A(x, y) on the assumption of

∃y.∀x.A(x, y)

We have an existential assumption, so stripping off the quantifier we can by the rule (∃E) use instead the assumption

∀x.A(x, y) Using (∀E) we have

∀x.A(x, y)

1.2. PREDICATE LOGIC 27 and by (∃I)

.. .

∃y.A(x, y)(∃I) Now, we can deduce

.. .

∀x.∃y.A(x, y)(∀I)

using (∀I), sincexis not free in the assumptions (and therefore arbitrary). We complete the proof with applications of (∃E) and (⇒I):

[∃y.∀x.A(x, y)]2 [∀x.A(x, y)]1 A(x, y) (∀E) ∃y.A(x, y) (∃I) ∀x.∃y.A(x, y) (∀I) ∀x.∃y.A(x, y) (∃E)1 ∃y.∀x.A(x, y)⇒ ∀x.∃y.A(x, y) (⇒I)2 Exercises

1.13. Explain how the side conditions in the proof rules prevent the con- struction of a proof of

∀x.∃y.A(x, y)⇒ ∃y.∀x.A(x, y) analogous to the proof of

∃y.∀x.A(x, y)⇒ ∀x.∃y.A(x, y) above.

1.14. Assuming that the variablexis not free inB, prove that the following formulas are equivalent,i.e. each can be proved on the assumption of the other

∀x.(A(x)⇒B) ((∃x.A(x))⇒B)

1.15. Using the previous exercise, or otherwise, argue that the following formulas are equivalent:

¬(∃x.A(x)) ∀x.¬A(x) and show that

∃x.¬A(x)⇒ ¬∀x.A(x)

Chapter 2

Functional Programming

and

λ-Calculi

Type theory has aspects of both a logic and a functional programming lan- guage. We have seen a brief introduction to logic in chapter 1; here we first survey current practice in functional programming and then look at a number ofλ-calculi, which are formal theories of functions. Theλ-calculus was invented in the nineteen thirties by Church as a notation for functions, with the aim of developing a foundation for mathematics. As with much of the work of that time, the original aim was not met, but the subject itself has become an object of study in its own right. Interest in the λ-calculus has grown again in the last two decades as it has found a role in the foun- dations of computing science, in particular through its model theory, which underpins much of denotational semantics. The theory usually studied is the untyped λ-calculus, and we look at this first. We are lucky to have the encyclopaedic [Bar84] to refer to for proofs, bibliographic and historical information and so forth. Any important result in the untyped λ-calculus is to be found there, together with (at least!) one proof of it.

Running through our material, we first look at variable binding and sub- stitution, which are central to the λ-calculus. Variables are bound when a function is formed by abstraction, and when a function is applied, the formal parameters are replaced by their actual counterparts by substitu- tion. We then look at the relations of evaluation, or reduction, ‘→→’ and convertibility ‘↔↔’, the latter of which represents a form of equality over theλ-expressions. We discuss these from a general standpoint, which will form a foundation for similar discussions for type theory. In particular we look at the determinacy of computation (the Church-Rosser property)

and termination properties of evaluation, or as they are more commonly known, thenormalisationproperties of expressions. We draw a distinction between different kinds of reduction rule — the computation and equiv- alence rules — which again we will carry through into the body of the book. After a short look at the expressiveness of the untyped system, we turn to an examination of typed theories, which more closely reflect current functional programming practice. We highlight the difference between the typed and untyped by showing that the former is strongly normalising — all evaluation sequences are finite, meaning that, in particular, every pro- gram terminates. We give a proof of this theorem, which forms a model for other results of this sort in its proof by induction over types and its formulation of a strong induction hypothesis, a method first introduced by William Tait. Augmenting the type structure with product types and nat- ural numbers, we finish by returning to the discussion of computation and equivalence rules in the context of a typed language.

The survey [Hue90b] gives a useful overview of typedλ-calculi.

2.1

Functional Programming

The functional style of programming has been growing in popularity over the last thirty years, from its beginnings in early dialects of LISP, to the present day and the availability of a number of production-quality lan- guages like Haskell, Hope, Miranda, and Standard ML (SML) amongst others [HW90, BMS80, Tur85, Har86]. Although there are differences be- tween them, there is a wide degree of consensus about the form of the systems, which provide

First-class functions: Functions may be passed as arguments to and re- turned as results of other functions; they may form components of composite data structures and so on. An example is the mapfunc- tion. It takes a function, fsay, as argument, returning the function which takes a list, x say, as argument and returns the list resulting from applying fto every item inx.

Strong type systems: The language contains distinctions between dif- ferent values, classing similar values into types. The typing of values restricts the application of operators and data constructors, so that errors in which, for example, two boolean values are added, will not be permitted. Moreover, and this is what is meant by the adjective ‘strong’, no run-time errors can arise through type mismatches.

Polymorphic types: A potential objection to strong typing runs thus: in an untyped language we can re-use the same code for the identity

2.1. FUNCTIONAL PROGRAMMING 31 function over every type, after all it simply returns its argument. Sim- ilarly we can re-use the code to reverse a linked list over structurally similar lists (which only differ in the type of entries at each node) as the code is independent of the contents. We can accommodate this kind of genericity and retain strong typing if we use the Hindley- Milner type system, [Mil78], or other sorts of polymorphic type. The type of the identity function becomes* -> *, where*is a type vari- able, indicating that the type of the function is a functional type, in which the domain and range type are the same. This means that it can be used on booleans, returning a boolean, on numeric functions returning a numeric function, and so on.

Algebraic types: Lists, trees, and other types can be defined directly by recursive definitions, rather than through pointer types. The mechanism of algebraic types generalises enumerated types, (variant) records, certain sorts of pointer type definitions, and also permits type definitions (like those of lists) to be parametrised over types (like the type of their contents). Pattern matching is usually the means by which case analyses and selections of components are performed.

Modularity: The languages provide systems of modules of varying degrees of complexity by means of which large systems can be developed more easily.

One area in which there are differences is in the mechanism of evaluation. The SML system incorporates strict evaluation, under which scheme ar- guments of functions are evaluated before the instantiated function body, and components of data types are fully evaluated on object formation. On the other hand, Miranda and Haskell adopt lazy evaluation, under which function arguments and data type components are only evaluated when this becomes necessary, if at all. This permits a distinctive style of pro- gramming based on infinite and partially-defined data structures. There are advantages of each system, and indeed there are hybrids like Hope+ [Per89] which combine the two.

This is not the place to give a complete introduction to functional pro- gramming. There is a growing number of good introductory textbooks on the subject [BW88, Rea89, Wik87], as well as books looking at the foundations of the subject [Hue90a] and at current research directions [Pey87, Tur90]. We shall look at the topics described above as we de- velop our system of type theory; first, though, we investigate the lambda calculus, which is both a precursor of current functional programming lan- guages, having been developed in the nineteen thirties, and an abstract version of them.

In what follows we use the phrase ‘languages like Miranda’ – it is meant to encompass all the languages discussed above rather than simply Miranda.