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 *)