ion makes it possible to build non-recursive functions directly inside Calculus of Constructions terms, without giving a name to them, but for recursive functions the Fixpoint command always gives a name to the defined function. It mixes the two operations: first the description of a recursive function, second the definition of a constant having this function as value. With the fix construct, we can have only the first operation; in this sense, it is similar to the abstraction construct. Here is the syntax for this construct: As with the Fixpoint command, the {struct ai} is not mandatory if p = l. In the particular case where one defines only one recursive function the two occurrences of the identifier f must coincide. This identifier is used to denote the recursive function being defined but it can only be used inside the expression expr. The similarity between Fixpoint and fix makes it easier to understand the need for the various parts of this construct. For instance, the mul t2 function could also have been declared in the following manner: Definition mult2' : nat~nat := fix f (n:nat) : nat .= match n with 0 =} 0 I S p =} S (S (f p)) end. Here we have willingly changed the name given to the recursive function inside the fix construct to underline the fact that f is bound only inside the construct. Thus, this identifier has no relation with the name under which the function will be known. 6.4 Polymorphic Types 175 6.4 Polymorphic Types Among the operations that one can perform on binary trees carrying integer values, many rely only on the tree structure, but are independent of the fact that the values are integer values. For instance, we can compute the size or the height of a tree without looking at the values. It is sensible to define a general type of tree, in which the type of elements is left as a parameter, and use instances of this general type according to the needs of our algorithms. This is similar to the polymorphic data structures available in conventional functional languages, or the generic data structures of Ada. We describe this notion of polymorphism on lists, pairs, etc. 6.4.1 Polymorphic Lists The Coq system provides a theory of polymorphic lists in the package List. Require Import List. Print list. Inductive list (A : Set) : Set := nil : list A / cons : A -+ list A -+ list A For nil: Argument A is implicit For cons: Argument A is implicit For list: Argument scope is [type_scope] For nil: Argument scope is [type_scope] For cons: Argument scopes are [type_scope __ ] The Coq system provides a notation for lists, so that the expression" cons a l" is actually denoted "a: : l." We see here that the inductive type being defined does not occur as a simple identifier, but as a dependent type with one argument. The value of this argument is always A, the parameter of the definition, as given in the first line of the definition. This definition behaves as if we were actually defining a whole family of inductive types, indexed over the sort Set. This illustrates the construction of higher-order types that we saw in Chap. 4. There may be several parameters in an inductive definition. When parameters are provided, they must appear at every use of the type being defined. Everything happens as if the inductive type had been declared in a section, with a context where A is bound as a variable. Thus, the definition above is equivalent to a definition of the following form: Section define_lists. Variable A : Set. Inductive list' : Set := I nil' : list' I cons' : A -+ list' -+ list'. End define_lists. 176 6 Inductive Data Types This analogy between polymorphic inductive types and simple inductive types defined inside a section is helpful to understand the form of the induction principle. Let us first study the type of the induction principle as it would have been constructed inside the section: list'_indO : 'v'P : list' --+Prop, P nil' --+ ('v'(x:A)(l:list'), P 1 --+ P (cons' x 1»--+ 'v'x:list', P x. When the section is closed, the variable A is discharged, the type list' must be abstracted over A, the constructors, too, and the induction principle must take these changes into account: Check list'. list' : Set--+Set Check nil'. nil' : 'v' A:Set, list' A Check cons'. cons' : 'v' A:Set, A --+ list' A --+ list' A Check list'_ind. list' ind: 'v' (A:Set)(P:list' A --+ Prop), P (nil' A) --+{V (a:A)(l:list' A), P l--+ P (cons' A a l)) --+ 'v' l:list' A, P l From a practical point of view, an important characteristic of parametric inductive definitions is that the universal quantification appears before the universal quantification over the property that is the object of the proof by induction. This characteristic will be important in comparison with the inductive principles for inductive definitions of variably dependent types (see Sect. 6.5.2) Recursive functions and pattern matching on polymorphic types can be performed in the same manner as for the inductive types of the previous sections. However, there is an important difference; the parameters must not appear in the left-hand side of pattern matching clauses. For instance, the function to concatenate polymorphic lists is defined by an expression of this form: Fixpoint app (A:Set) (1 m:list A){struct I} : list A := match 1 with I nil :::} m I cons a 11 :::} cons a (app A 11 m) end. In this pattern matching construct, nil appears in the left-hand side of its clause without its Set argument. The same occurs for the cons constructor, 6.4 Polymorphic Types 177 even though cons normally has three arguments; the pattern only has two. The reasoh for removing the parameter arguments from the constructors is that these parameters cannot be bound in the pattern. The type A for the values is already fixed because an expression of type "list A" is being analyzed by the pattern matching construct. In the right-hand side of the second clause, cons also appears with two arguments, but this is because the function is defined with the first argument being implicit (see Sect. 4.2.3.1). Use of implicit arguments for functions manipulating polymorphic types is frequent. For instance, the function app also has its first argument as an implicit argument. For this function, the Coq system also provides an infix notation, where "app h h" is actually denoted "h++h." Exercise 6.34 Build a polymorphic function that takes a list as argument and returns a list containing the first two elements when they exist. Exercise 6.35 Build a function that takes a natural number, n, and a list as arguments and returns the list containing the first n elements of the list when they exist. Exercise 6.36 Build a function that takes a list of integers as argument and returns the sum of these numbers. Exercise 6.37 Build a function that takes a natural number n as argument and builds a list containing n occurrences of the number one. Exercise 6.38 Build a function that takes a number n and returns the list containing the integers from 1 to n, in this order. 6.4.2 The option Type Polymorphic types need not be truly recursive. A frequent example is the option type that is well-adapted to describe a large class of partial functions. This type is also present in conventional functional programming languages. Its inductive definition has the following form: Print option. Inductive option (A:Set) : Set := Some: A-+option A / None: option A For Some: Argument A is implicit For None: Argument A is implicit For option: Argument scope is [type_scope] For Some: Argument scopes are [type_scope _] For None: Argument scope is [type_scope] 178 6 Inductive Data Types When we need to define a function that is not total from a type A to a type B, it is often possible to describe it as a total function from A to "option B," with the convention that the value "None" is the result when the function is not defined and the value is "Some y" when the function would have been defined with value y. For instance, the Coq library contains a pred function of type nat---+nat that maps any natural number to its predecessor (when it exists) and maps zero to itself. A partial function could have been defined that does not have a value for the number zero. The definition would have been as follows: Definition pred_option (n:nat) : option nat := match n with 0 => None I S P => Some pend. To use a value of the option type, a case analysis is necessary, to express explicitly how the computation proceeds when no true value is given. For instance, the function that returns the predecessor's predecessor can be defined as follows: Definition pred2_option (n:nat) : option nat := match pred_option n with I None => None I Some p => pred_option p end. As a second example, we can consider the function that returns the nth element of a list. The Coq library provides a function called nth for this requirement but that function takes an extra argument which is used for the result when the list has less than n elements. An alternative could be to define a function whose result belongs in the option type. This function can be defined using simultaneous pattern matching on the number and the list. Both arguments decrease at each recursive call, so that the principal recursion argument could be either of them. Here is one of the two possible versions: Fixpoint nth_option (A:Set) (n:nat) (l:list A){struct l} : option A := match n, 1 with I 0, cons a tl => Some a I S p, cons a tl => nth_option A p tl I n, nil => None end. Exercise 6.39 Define the other variant "nth_option'." The arguments are given in the same order, but the principal argument is the number n. Prove that both functions always give the same result when applied on the same input. Exercise 6.40 * Prove V(A:Set)(n:nat)(l:list A), nth_option A n 1 = None ---+ length 1 < n. 6.4 Polymorphic Types 179 Exercise 6.41 * Define a function that maps a type A in sort Set, a function f of type A---+booL, and a list L to the first element :z: in L such that "f x" is true. 6.4.3 The Type of Pairs Pairs prov
[1]
Catherine Parent,et al.
Synthesizing Proofs from Programs in the Calculus of Inductive Constructions
,
1995,
MPC.
[2]
Frédéric Loulergue,et al.
Développement d'applications avec Objective CAML by E. Chailloux, P. Manoury and B. Pagano, O'Reilley, 2003
,
2004,
Journal of functional programming.
[3]
Zhaohui Luo,et al.
Computation and reasoning - a type theory for computer science
,
1994,
International series of monographs on computer science.
[4]
Samuel Boutin,et al.
Using Reflection to Build Efficient and Certified Decision Procedures
,
1997,
TACS.
[5]
Line Jakubiec,et al.
Hardware Verification Using Co-induction in COQ
,
1999,
TPHOLs.
[6]
A. Heyting,et al.
Intuitionism: An introduction
,
1956
.
[7]
Eduardo Giménez,et al.
An Application of Co-inductive Types in Coq: Verification of the Alternating Bit Protocol
,
1995,
TYPES.
[8]
Thierry Coquand,et al.
An Analysis of Girard's Paradox
,
1986,
LICS.
[9]
C. Paulin-Mohring.
Définitions Inductives en Théorie des Types
,
1996
.
[10]
Venanzio Capretta,et al.
Type-Theoretic Functional Semantics
,
2002,
TPHOLs.
[11]
Christine Paulin-Mohring,et al.
Inductive Definitions in the system Coq - Rules and Properties
,
1993,
TLCA.
[12]
Peter Aczel,et al.
An Introduction to Inductive Definitions
,
1977
.
[13]
D. Prawitz.
Ideas and Results in Proof Theory
,
1971
.
[14]
D. Delahaye,et al.
Conception de langages pour décrire les preuves et les automatisations dans les outils d'aide à la preuve : une étude dans le cadre du système Coq
,
2001
.
[15]
R. Montague,et al.
The Semantic Conception of Truth and the Foundations of Semantics
,
1996
.
[16]
Larry C. Paulson,et al.
ML for the Working Programmer: PREDECLARED IDENTIFIERS
,
1996
.
[17]
T. Coquand,et al.
Metamathematical investigations of a calculus of constructions
,
1989
.
[18]
Solange Coupet-Grimal,et al.
An Axiomatization of Linear Temporal Logic in the Calculus of Inductive Constructions
,
2003,
J. Log. Comput..
[19]
Conor McBride,et al.
Elimination with a Motive
,
2000,
TYPES.
[20]
J. Girard,et al.
Proofs and types
,
1989
.
[21]
Robert S. Boyer,et al.
A computational logic handbook
,
1979,
Perspectives in computing.
[22]
Hendrik Pieter Barendregt,et al.
Introduction to generalized type systems
,
1991,
Journal of Functional Programming.
[23]
Olga Caprotti,et al.
Formal and Efficient Primality Proofs by Use of Computer Algebra Oracles
,
2001,
J. Symb. Comput..
[24]
Yves Bertot,et al.
Fix-Point Equations for Well-Founded Recursion in Type Theory
,
2000,
TPHOLs.
[25]
Lawrence C. Paulson,et al.
The foundation of a generic theorem prover
,
1989,
Journal of Automated Reasoning.
[26]
Xavier Leroy,et al.
Manifest types, modules, and separate compilation
,
1994,
POPL '94.
[27]
Christine Paulin-Mohring,et al.
Synthesis of ML Programs in the System Coq
,
1993,
J. Symb. Comput..
[28]
Ana Bove,et al.
Simple General Recursion in Type Theory
,
2001,
Nord. J. Comput..
[29]
Robin Milner,et al.
Edinburgh lcf: a mechanized logic of computation
,
1978
.
[30]
M. Gordon,et al.
Introduction to HOL: a theorem proving environment for higher order logic
,
1993
.
[31]
Nicolas Magaud,et al.
A Proof of GMP Square Root
,
2004,
Journal of Automated Reasoning.
[32]
Conor McBride,et al.
The view from the left
,
2004,
Journal of Functional Programming.
[33]
Xavier Leroy,et al.
A modular module system
,
2000,
J. Funct. Program..
[34]
R. Dedekind,et al.
Was sind und was sollen die Zahlen
,
1961
.
[35]
Yves Bertot,et al.
Reasoning with Executable Specifications
,
1995,
TAPSOFT.
[36]
Pierre Letouzey,et al.
A New Extraction for Coq
,
2002,
TYPES.
[37]
Jean-Christophe Filliâtre,et al.
Verification of non-functional programs using interpretations in type theory
,
2003,
J. Funct. Program..
[38]
Pierre Courtieu,et al.
Efficient Reasoning about Executable Specifications in Coq
,
2002,
TPHOLs.
[39]
C. A. R. HOARE,et al.
An axiomatic basis for computer programming
,
1969,
CACM.
[40]
Gregory H. Moore.
From frege to Gödel: A source book in mathematical logic, 1879–1931: Edited by Jean van Heijenoort. Cambridge (Harvard University Press). 1971. xi + 660 pp. Second corrected printing
,
1977
.
[41]
Alonzo Church,et al.
A formulation of the simple theory of types
,
1940,
Journal of Symbolic Logic.
[42]
Cuihtlauac Alvarado.
Réflexion pour la réécriture dans le calcul des constructions inductives
,
2002
.
[43]
Amir Pnueli,et al.
The temporal logic of programs
,
1977,
18th Annual Symposium on Foundations of Computer Science (sfcs 1977).
[44]
Robert W. Floyd,et al.
Assigning Meanings to Programs
,
1993
.
[45]
Thierry Coquand,et al.
The Calculus of Constructions
,
1988,
Inf. Comput..
[46]
Fa Dick.
The mathematical language AUTOMATH, its usage and some of its extensions
,
1970
.
[47]
Peter Dybjer,et al.
A general formulation of simultaneous inductive-recursive definitions in type theory
,
2000,
Journal of Symbolic Logic.
[48]
Edsger W. Dijkstra,et al.
A Discipline of Programming
,
1976
.
[49]
Rance Cleaveland,et al.
Implementing mathematics with the Nuprl proof development system
,
1986
.
[50]
Assia Mahboubi,et al.
Élimination des quantificateurs sur les réels pour Coq
,
2002
.
[51]
Robert S. Boyer,et al.
Proving Theorems about LISP Functions
,
1973,
JACM.
[52]
William A. Howard,et al.
The formulae-as-types notion of construction
,
1969
.
[53]
Gérard P. Huet,et al.
Induction Principles Formalized in the Calculus of Constructions
,
1987,
TAPSOFT, Vol.1.
[54]
Laurent Théry,et al.
A Certified Version of Buchberger's Algorithm
,
1998,
CADE.
[55]
Natarajan Shankar,et al.
PVS: Combining Specification, Proof Checking, and Model Checking
,
1996,
FMCAD.
[56]
William Pugh,et al.
The Omega test: A fast and practical integer programming algorithm for dependence analysis
,
1991,
Proceedings of the 1991 ACM/IEEE Conference on Supercomputing (Supercomputing '91).
[57]
John C. Mitchell,et al.
Type Systems for Programming Languages
,
1991,
Handbook of Theoretical Computer Science, Volume B: Formal Models and Sematics.
[58]
Jan M. Smith,et al.
Martin-Löf's type theory
,
2001,
LICS 2001.