Mercurial > cpdt > repo
comparison src/InductiveTypes.v @ 316:2aaff91f5258
Pass through InductiveTypes, through end of reflexive types
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Sun, 11 Sep 2011 17:22:36 -0400 |
parents | 72bffb046797 |
children | 50db9a6e2742 |
comparison
equal
deleted
inserted
replaced
315:72bffb046797 | 316:2aaff91f5258 |
---|---|
164 | 164 |
165 Inductive bool : Set := | 165 Inductive bool : Set := |
166 | true | 166 | true |
167 | false. | 167 | false. |
168 | 168 |
169 (** We can use less vacuous pattern matching to define boolean negation. *) | 169 (** We can use less vacuous pattern matching to define boolean negation.%\index{Gallina terms!negb}% *) |
170 | 170 |
171 Definition negb (b : bool) : bool := | 171 Definition negb (b : bool) : bool := |
172 match b with | 172 match b with |
173 | true => false | 173 | true => false |
174 | false => true | 174 | false => true |
242 | O : nat | 242 | O : nat |
243 | S : nat -> nat. | 243 | S : nat -> nat. |
244 | 244 |
245 (** [O] is zero, and [S] is the successor function, so that [0] is syntactic sugar for [O], [1] for [S O], [2] for [S (][S O)], and so on. | 245 (** [O] is zero, and [S] is the successor function, so that [0] is syntactic sugar for [O], [1] for [S O], [2] for [S (][S O)], and so on. |
246 | 246 |
247 Pattern matching works as we demonstrated in the last chapter: *) | 247 Pattern matching works as we demonstrated in the last chapter:%\index{Gallina terms!pred}% *) |
248 | 248 |
249 Definition isZero (n : nat) : bool := | 249 Definition isZero (n : nat) : bool := |
250 match n with | 250 match n with |
251 | O => true | 251 | O => true |
252 | S _ => false | 252 | S _ => false |
264 (* begin thide *) | 264 (* begin thide *) |
265 destruct n; reflexivity. | 265 destruct n; reflexivity. |
266 Qed. | 266 Qed. |
267 (* end thide *) | 267 (* end thide *) |
268 | 268 |
269 (** We can also now get into genuine inductive theorems. First, we will need a recursive function, to make things interesting. *) | 269 (** We can also now get into genuine inductive theorems. First, we will need a recursive function, to make things interesting.%\index{Gallina terms!plus}% *) |
270 | 270 |
271 Fixpoint plus (n m : nat) : nat := | 271 Fixpoint plus (n m : nat) : nat := |
272 match n with | 272 match n with |
273 | O => m | 273 | O => m |
274 | S n' => S (plus n' m) | 274 | S n' => S (plus n' m) |
441 We have the usual two cases, one for each constructor of [nat_btree]. *) | 441 We have the usual two cases, one for each constructor of [nat_btree]. *) |
442 | 442 |
443 | 443 |
444 (** * Parameterized Types *) | 444 (** * Parameterized Types *) |
445 | 445 |
446 (** We can also define polymorphic inductive types, as with algebraic datatypes in Haskell and ML. *) | 446 (** We can also define %\index{polymorphism}%polymorphic inductive types, as with algebraic datatypes in Haskell and ML.%\index{Gallina terms!list}\index{Gallina terms!Nil}\index{Gallina terms!Cons}\index{Gallina terms!length}\index{Gallina terms!app}% *) |
447 | 447 |
448 Inductive list (T : Set) : Set := | 448 Inductive list (T : Set) : Set := |
449 | Nil : list T | 449 | Nil : list T |
450 | Cons : T -> list T -> list T. | 450 | Cons : T -> list T -> list T. |
451 | 451 |
466 (* begin thide *) | 466 (* begin thide *) |
467 induction ls1; crush. | 467 induction ls1; crush. |
468 Qed. | 468 Qed. |
469 (* end thide *) | 469 (* end thide *) |
470 | 470 |
471 (** There is a useful shorthand for writing many definitions that share the same parameter, based on Coq's %\textit{%#<i>#section#</i>#%}% mechanism. The following block of code is equivalent to the above: *) | 471 (** There is a useful shorthand for writing many definitions that share the same parameter, based on Coq's %\index{sections}\index{Vernacular commands!Section}\index{Vernacular commands!Variable}\textit{%#<i>#section#</i>#%}% mechanism. The following block of code is equivalent to the above: *) |
472 | 472 |
473 (* begin hide *) | 473 (* begin hide *) |
474 Reset list. | 474 Reset list. |
475 (* end hide *) | 475 (* end hide *) |
476 | 476 |
508 (** After we end the section, the [Variable]s we used are added as extra function parameters for each defined identifier, as needed. We verify that this has happened using the [Print] command, a cousin of [Check] which shows the definition of a symbol, rather than just its type. *) | 508 (** After we end the section, the [Variable]s we used are added as extra function parameters for each defined identifier, as needed. We verify that this has happened using the [Print] command, a cousin of [Check] which shows the definition of a symbol, rather than just its type. *) |
509 | 509 |
510 Print list. | 510 Print list. |
511 (** %\vspace{-.15in}% [[ | 511 (** %\vspace{-.15in}% [[ |
512 Inductive list (T : Set) : Set := | 512 Inductive list (T : Set) : Set := |
513 Nil : list T | Cons : T -> list T -> list Tlist | 513 Nil : list T | Cons : T -> list T -> list T |
514 | 514 |
515 ]] | 515 ]] |
516 | 516 |
517 The final definition is the same as what we wrote manually before. The other elements of the section are altered similarly, turning out exactly as they were before, though we managed to write their definitions more succinctly. *) | 517 The final definition is the same as what we wrote manually before. The other elements of the section are altered similarly, turning out exactly as they were before, though we managed to write their definitions more succinctly. *) |
518 | 518 |
596 (forall (n : nat) (o : odd_list), P (ECons n o)) -> | 596 (forall (n : nat) (o : odd_list), P (ECons n o)) -> |
597 forall e : even_list, P e | 597 forall e : even_list, P e |
598 | 598 |
599 ]] | 599 ]] |
600 | 600 |
601 We see that no inductive hypotheses are included anywhere in the type. To get them, we must ask for mutual principles as we need them, using the [Scheme] command. *) | 601 We see that no inductive hypotheses are included anywhere in the type. To get them, we must ask for mutual principles as we need them, using the %\index{Vernacular commands!Scheme}%[Scheme] command. *) |
602 | 602 |
603 Scheme even_list_mut := Induction for even_list Sort Prop | 603 Scheme even_list_mut := Induction for even_list Sort Prop |
604 with odd_list_mut := Induction for odd_list Sort Prop. | 604 with odd_list_mut := Induction for odd_list Sort Prop. |
605 | |
606 (** This invocation of [Scheme] asks for the creation of induction principles [even_list_mut] for the type [even_list] and [odd_list_mut] for the type [odd_list]. The [Induction] keyword says we want standard induction schemes, since [Scheme] supports more exotic choices. Finally, [Sort Prop] establishes that we really want induction schemes, not recursion schemes, which are the same according to Curry-Howard, save for the [Prop]/[Set] distinction. *) | |
605 | 607 |
606 Check even_list_mut. | 608 Check even_list_mut. |
607 (** %\vspace{-.15in}% [[ | 609 (** %\vspace{-.15in}% [[ |
608 even_list_mut | 610 even_list_mut |
609 : forall (P : even_list -> Prop) (P0 : odd_list -> Prop), | 611 : forall (P : even_list -> Prop) (P0 : odd_list -> Prop), |
612 (forall (n : nat) (e : even_list), P e -> P0 (OCons n e)) -> | 614 (forall (n : nat) (e : even_list), P e -> P0 (OCons n e)) -> |
613 forall e : even_list, P e | 615 forall e : even_list, P e |
614 | 616 |
615 ]] | 617 ]] |
616 | 618 |
617 This is the principle we wanted in the first place. There is one more wrinkle left in using it: the [induction] tactic will not apply it for us automatically. It will be helpful to look at how to prove one of our past examples without using [induction], so that we can then generalize the technique to mutual inductive types. *) | 619 This is the principle we wanted in the first place. There is one more wrinkle left in using it: the [induction] tactic will not apply it for us automatically. It will be helpful to look at how to prove one of our past examples without using [induction], so that we can then generalize the technique to mutual inductive types.%\index{tactics!apply}% *) |
618 | 620 |
619 Theorem n_plus_O' : forall n : nat, plus n O = n. | 621 Theorem n_plus_O' : forall n : nat, plus n O = n. |
620 apply (nat_ind (fun n => plus n O = n)); crush. | 622 apply (nat_ind (fun n => plus n O = n)); crush. |
621 Qed. | 623 Qed. |
622 | 624 |
638 (** We simply need to specify two predicates, one for each of the mutually inductive types. In general, it would not be a good idea to assume that a proof assistant could infer extra predicates, so this way of applying mutual induction is about as straightforward as we could hope for. *) | 640 (** We simply need to specify two predicates, one for each of the mutually inductive types. In general, it would not be a good idea to assume that a proof assistant could infer extra predicates, so this way of applying mutual induction is about as straightforward as we could hope for. *) |
639 | 641 |
640 | 642 |
641 (** * Reflexive Types *) | 643 (** * Reflexive Types *) |
642 | 644 |
643 (** A kind of inductive type called a %\textit{%#<i>#reflexive type#</i>#%}% is defined in terms of functions that have the type being defined as their range. One very useful class of examples is in modeling variable binders. For instance, here is a type for encoding the syntax of a subset of first-order logic: *) | 645 (** A kind of inductive type called a %\textit{%#<i>#reflexive type#</i>#%}% is defined in terms of functions that have the type being defined as their range. One very useful class of examples is in modeling variable binders. Our example will be an encoding of the syntax of first-order logic. Since the idea of syntactic encodings of logic may require a bit of acclimation, let us first consider a simpler formula type for a subset of propositional logic. *) |
646 | |
647 Inductive pformula : Set := | |
648 | Truth : pformula | |
649 | Falsehood : pformula | |
650 | Conjunction : pformula -> pformula -> pformula. | |
651 | |
652 (** A key distinction here is between, for instance, the %\emph{%#<i>#syntax#</i>#%}% [Truth] and its %\emph{%#<i>#semantics#</i>#%}% [True]. We can make the semantics explicit with a recursive function. This function uses the infix operator %\index{Gallina operators!/\textbackslash}%[/\], which desugars to uses of the type family %\index{Gallina terms!conj}%[conj] from the standard library. The family [conj] implements conjunction (i.e., %``%#"#and#"#%''%), the [Prop] Curry-Howard analogue of the usual pair type from functional programming (which is the type family %\index{Gallina terms!prod}%[prod] in Coq's standard library). *) | |
653 | |
654 Fixpoint pformulaDenote (f : pformula) : Prop := | |
655 match f with | |
656 | Truth => True | |
657 | Falsehood => False | |
658 | Conjunction f1 f2 => pformulaDenote f1 /\ pformulaDenote f2 | |
659 end. | |
660 | |
661 (** This is a just a warm-up that does not use reflexive types, the new feature we mean to introduce. When we set our sights on first-order logic instead, it becomes very handy to give constructors recursive arguments that are functions. *) | |
644 | 662 |
645 Inductive formula : Set := | 663 Inductive formula : Set := |
646 | Eq : nat -> nat -> formula | 664 | Eq : nat -> nat -> formula |
647 | And : formula -> formula -> formula | 665 | And : formula -> formula -> formula |
648 | Forall : (nat -> formula) -> formula. | 666 | Forall : (nat -> formula) -> formula. |
649 | 667 |
650 (** Our kinds of formulas are equalities between naturals, conjunction, and universal quantification over natural numbers. We avoid needing to include a notion of %``%#"#variables#"#%''% in our type, by using Coq functions to encode quantification. For instance, here is the encoding of [forall x : nat, x = x]: *) | 668 (** Our kinds of formulas are equalities between naturals, conjunction, and universal quantification over natural numbers. We avoid needing to include a notion of %``%#"#variables#"#%''% in our type, by using Coq functions to encode quantification. For instance, here is the encoding of [forall x : nat, x = x]:%\index{Vernacular commands!Example}% *) |
651 | 669 |
652 Example forall_refl : formula := Forall (fun x => Eq x x). | 670 Example forall_refl : formula := Forall (fun x => Eq x x). |
653 | 671 |
654 (** We can write recursive functions over reflexive types quite naturally. Here is one translating our formulas into native Coq propositions. *) | 672 (** We can write recursive functions over reflexive types quite naturally. Here is one translating our formulas into native Coq propositions. *) |
655 | 673 |
694 | 712 |
695 Focusing on the [Forall] case, which comes third, we see that we are allowed to assume that the theorem holds %\textit{%#<i>#for any application of the argument function [f1]#</i>#%}%. That is, Coq induction principles do not follow a simple rule that the textual representations of induction variables must get shorter in appeals to induction hypotheses. Luckily for us, the people behind the metatheory of Coq have verified that this flexibility does not introduce unsoundness. | 713 Focusing on the [Forall] case, which comes third, we see that we are allowed to assume that the theorem holds %\textit{%#<i>#for any application of the argument function [f1]#</i>#%}%. That is, Coq induction principles do not follow a simple rule that the textual representations of induction variables must get shorter in appeals to induction hypotheses. Luckily for us, the people behind the metatheory of Coq have verified that this flexibility does not introduce unsoundness. |
696 | 714 |
697 %\medskip% | 715 %\medskip% |
698 | 716 |
699 Up to this point, we have seen how to encode in Coq more and more of what is possible with algebraic datatypes in Haskell and ML. This may have given the inaccurate impression that inductive types are a strict extension of algebraic datatypes. In fact, Coq must rule out some types allowed by Haskell and ML, for reasons of soundness. Reflexive types provide our first good example of such a case. | 717 Up to this point, we have seen how to encode in Coq more and more of what is possible with algebraic datatypes in %\index{Haskell}%Haskell and %\index{ML}%ML. This may have given the inaccurate impression that inductive types are a strict extension of algebraic datatypes. In fact, Coq must rule out some types allowed by Haskell and ML, for reasons of soundness. Reflexive types provide our first good example of such a case. |
700 | 718 |
701 Given our last example of an inductive type, many readers are probably eager to try encoding the syntax of lambda calculus. Indeed, the function-based representation technique that we just used, called %\textit{%#<i>#higher-order abstract syntax (HOAS)#</i>#%}%, is the representation of choice for lambda calculi in Twelf and in many applications implemented in Haskell and ML. Let us try to import that choice to Coq: *) | 719 Given our last example of an inductive type, many readers are probably eager to try encoding the syntax of %\index{lambda calculus}%lambda calculus. Indeed, the function-based representation technique that we just used, called %\index{higher-order abstract syntax}\index{HOAS|see{higher-order abstract syntax}}\textit{%#<i>#higher-order abstract syntax (HOAS)#</i>#%}~\cite{HOAS}%, is the representation of choice for lambda calculi in %\index{Twelf}%Twelf and in many applications implemented in Haskell and ML. Let us try to import that choice to Coq: *) |
702 | |
703 (** [[ | 720 (** [[ |
704 Inductive term : Set := | 721 Inductive term : Set := |
705 | App : term -> term -> term | 722 | App : term -> term -> term |
706 | Abs : (term -> term) -> term. | 723 | Abs : (term -> term) -> term. |
707 | 724 ]] |
725 | |
726 << | |
708 Error: Non strictly positive occurrence of "term" in "(term -> term) -> term" | 727 Error: Non strictly positive occurrence of "term" in "(term -> term) -> term" |
709 | 728 >> |
710 ]] | 729 |
711 | 730 We have run afoul of the %\index{strict positivity requirement}\index{positivity requirement}\textit{%#<i>#strict positivity requirement#</i>#%}% for inductive definitions, which says that the type being defined may not occur to the left of an arrow in the type of a constructor argument. It is important that the type of a constructor is viewed in terms of a series of arguments and a result, since obviously we need recursive occurrences to the lefts of the outermost arrows if we are to have recursive occurrences at all. Our candidate definition above violates the positivity requirement because it involves an argument of type [term -> term], where the type [term] that we are defining appears to the left of an arrow. The candidate type of [App] is fine, however, since every occurrence of [term] is either a constructor argument or the final result type. |
712 We have run afoul of the %\textit{%#<i>#strict positivity requirement#</i>#%}% for inductive definitions, which says that the type being defined may not occur to the left of an arrow in the type of a constructor argument. It is important that the type of a constructor is viewed in terms of a series of arguments and a result, since obviously we need recursive occurrences to the lefts of the outermost arrows if we are to have recursive occurrences at all. | |
713 | 731 |
714 Why must Coq enforce this restriction? Imagine that our last definition had been accepted, allowing us to write this function: | 732 Why must Coq enforce this restriction? Imagine that our last definition had been accepted, allowing us to write this function: |
715 | 733 |
716 [[ | 734 [[ |
717 Definition uhoh (t : term) : term := | 735 Definition uhoh (t : term) : term := |
722 | 740 |
723 ]] | 741 ]] |
724 | 742 |
725 Using an informal idea of Coq's semantics, it is easy to verify that the application [uhoh (Abs uhoh)] will run forever. This would be a mere curiosity in OCaml and Haskell, where non-termination is commonplace, though the fact that we have a non-terminating program without explicit recursive function definitions is unusual. | 743 Using an informal idea of Coq's semantics, it is easy to verify that the application [uhoh (Abs uhoh)] will run forever. This would be a mere curiosity in OCaml and Haskell, where non-termination is commonplace, though the fact that we have a non-terminating program without explicit recursive function definitions is unusual. |
726 | 744 |
727 For Coq, however, this would be a disaster. The possibility of writing such a function would destroy all our confidence that proving a theorem means anything. Since Coq combines programs and proofs in one language, we would be able to prove every theorem with an infinite loop. | 745 %\index{termination checking}%For Coq, however, this would be a disaster. The possibility of writing such a function would destroy all our confidence that proving a theorem means anything. Since Coq combines programs and proofs in one language, we would be able to prove every theorem with an infinite loop. |
728 | 746 |
729 Nonetheless, the basic insight of HOAS is a very useful one, and there are ways to realize most benefits of HOAS in Coq. We will study a particular technique of this kind in the later chapters on programming language syntax and semantics. *) | 747 Nonetheless, the basic insight of HOAS is a very useful one, and there are ways to realize most benefits of HOAS in Coq. We will study a particular technique of this kind in the later chapters on programming language syntax and semantics. *) |
730 | 748 |
731 | 749 |
732 (** * An Interlude on Proof Terms *) | 750 (** * An Interlude on Proof Terms *) |