Mercurial > cpdt > repo
comparison src/InductiveTypes.v @ 34:d44274542f8b
Interlude on Proof Terms
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Wed, 10 Sep 2008 14:41:41 -0400 |
parents | 8b34dade70e1 |
children | 6d05ee182b65 |
comparison
equal
deleted
inserted
replaced
33:8b34dade70e1 | 34:d44274542f8b |
---|---|
636 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. | 636 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. |
637 | 637 |
638 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. | 638 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. |
639 | 639 |
640 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. *) | 640 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. *) |
641 | |
642 | |
643 (** * An Interlude on Proof Terms *) | |
644 | |
645 (** As we have emphasized a few times already, Coq proofs are actually programs, written in the same language we have been using in our examples all along. We can get a first sense of what this means by taking a look at the definitions of some of the induction principles we have used. *) | |
646 | |
647 Print unit_ind. | |
648 (** [[ | |
649 | |
650 unit_ind = | |
651 fun P : unit -> Prop => unit_rect P | |
652 : forall P : unit -> Prop, P tt -> forall u : unit, P u | |
653 ]] | |
654 | |
655 We see that this induction principle is defined in terms of a more general principle, [unit_rect]. *) | |
656 | |
657 Check unit_rect. | |
658 (** [[ | |
659 | |
660 unit_rect | |
661 : forall P : unit -> Type, P tt -> forall u : unit, P u | |
662 ]] | |
663 | |
664 [unit_rect] gives [P] type [unit -> Type] instead of [unit -> Prop]. [Type] is another universe, like [Set] and [Prop]. In fact, it is a common supertype of both. Later on, we will discuss exactly what the significances of the different universes are. For now, it is just important that we can use [Type] as a sort of meta-universe that may turn out to be either [Set] or [Prop]. We can see the symmetry inherent in the subtyping relationship by printing the definition of another principle that was generated for [unit] automatically: *) | |
665 | |
666 Print unit_rec. | |
667 (** [[ | |
668 | |
669 unit_rec = | |
670 fun P : unit -> Set => unit_rect P | |
671 : forall P : unit -> Set, P tt -> forall u : unit, P u | |
672 ]] | |
673 | |
674 This is identical to the definition for [unit_ind], except that we have substituted [Set] for [Prop]. For most inductive types [T], then, we get not just induction principles [T_ind], but also recursion principles [T_rec]. We can use [T_rec] to write recursive definitions without explicit [Fixpoint] recursion. For instance, the following two definitions are equivalent: *) | |
675 | |
676 Definition always_O (u : unit) : nat := | |
677 match u with | |
678 | tt => O | |
679 end. | |
680 | |
681 Definition always_O' (u : unit) : nat := | |
682 unit_rec (fun _ : unit => nat) O u. | |
683 | |
684 (** Going even further down the rabbit hole, [unit_rect] itself is not even a primitive. It is a functional program that we can write manually. *) | |
685 | |
686 Print unit_rect. | |
687 | |
688 (** [[ | |
689 | |
690 unit_rect = | |
691 fun (P : unit -> Type) (f : P tt) (u : unit) => | |
692 match u as u0 return (P u0) with | |
693 | tt => f | |
694 end | |
695 : forall P : unit -> Type, P tt -> forall u : unit, P u | |
696 ]] | |
697 | |
698 The only new feature we see is an [as] clause for a [match], which is used in concert with the [return] clause that we saw in the introduction. Since the type of the [match] is dependent on the value of the object being analyzed, we must give that object a name so that we can refer to it in the [return] clause. | |
699 | |
700 To prove that [unit_rect] is nothing special, we can reimplement it manually. *) | |
701 | |
702 Definition unit_rect' (P : unit -> Type) (f : P tt) (u : unit) := | |
703 match u return (P u) with | |
704 | tt => f | |
705 end. | |
706 | |
707 (** We use the handy shorthand that lets us omit an [as] annotation when matching on a variable, simply using that variable directly in the [return] clause. | |
708 | |
709 We can check the implement of [nat_rect] as well: *) | |
710 | |
711 Print nat_rect. | |
712 (** [[ | |
713 | |
714 nat_rect = | |
715 fun (P : nat -> Type) (f : P O) (f0 : forall n : nat, P n -> P (S n)) => | |
716 fix F (n : nat) : P n := | |
717 match n as n0 return (P n0) with | |
718 | O => f | |
719 | S n0 => f0 n0 (F n0) | |
720 end | |
721 : forall P : nat -> Type, | |
722 P O -> (forall n : nat, P n -> P (S n)) -> forall n : nat, P n | |
723 ]] | |
724 | |
725 Now we have an actual recursive definition. [fix] expressions are an anonymous form of [Fixpoint], just as [fun] expressions stand for anonymous non-recursive functions. Beyond that, the syntax of [fix] mirrors that of [Fixpoint]. We can understand the definition of [nat_rect] better by reimplementing [nat_ind] using sections. *) | |
726 | |
727 Section nat_ind'. | |
728 (** First, we have the property of natural numbers that we aim to prove. *) | |
729 Variable P : nat -> Prop. | |
730 | |
731 (** Then we require a proof of the [O] case. *) | |
732 Variable O_case : P O. | |
733 | |
734 (** Next is a proof of the [S] case, which may assume an inductive hypothesis. *) | |
735 Variable S_case : forall n : nat, P n -> P (S n). | |
736 | |
737 (** Finally, we define a recursive function to tie the pieces together. *) | |
738 Fixpoint nat_ind' (n : nat) : P n := | |
739 match n return (P n) with | |
740 | O => O_case | |
741 | S n' => S_case (nat_ind' n') | |
742 end. | |
743 End nat_ind'. | |
744 | |
745 (** Closing the section adds the [Variable]s as new [fun]-bound arguments to [nat_ind'], and, modulo the use of [Prop] instead of [Type], we end up with the exact same definition that was generated automatically for [nat_rect]. | |
746 | |
747 %\medskip% | |
748 | |
749 We can also examine the definition of [even_list_mut], which we generated with [Scheme] for a mutually-recursive type. *) | |
750 | |
751 Print even_list_mut. | |
752 (** [[ | |
753 | |
754 even_list_mut = | |
755 fun (P : even_list -> Prop) (P0 : odd_list -> Prop) | |
756 (f : P ENil) (f0 : forall (n : nat) (o : odd_list), P0 o -> P (ECons n o)) | |
757 (f1 : forall (n : nat) (e : even_list), P e -> P0 (OCons n e)) => | |
758 fix F (e : even_list) : P e := | |
759 match e as e0 return (P e0) with | |
760 | ENil => f | |
761 | ECons n o => f0 n o (F0 o) | |
762 end | |
763 with F0 (o : odd_list) : P0 o := | |
764 match o as o0 return (P0 o0) with | |
765 | OCons n e => f1 n e (F e) | |
766 end | |
767 for F | |
768 : forall (P : even_list -> Prop) (P0 : odd_list -> Prop), | |
769 P ENil -> | |
770 (forall (n : nat) (o : odd_list), P0 o -> P (ECons n o)) -> | |
771 (forall (n : nat) (e : even_list), P e -> P0 (OCons n e)) -> | |
772 forall e : even_list, P e | |
773 ]] | |
774 | |
775 We see a mutually-recursive [fix], with the different functions separated by [with] in the same way that they would be separated by [and] in ML. A final [for] clause identifies which of the mutually-recursive functions should be the final value of the [fix] expression. Using this definition as a template, we can reimplement [even_list_mut] directly. *) | |
776 | |
777 Section even_list_mut'. | |
778 (** First, we need the properties that we are proving. *) | |
779 Variable Peven : even_list -> Prop. | |
780 Variable Podd : odd_list -> Prop. | |
781 | |
782 (** Next, we need proofs of the three cases. *) | |
783 Variable ENil_case : Peven ENil. | |
784 Variable ECons_case : forall (n : nat) (o : odd_list), Podd o -> Peven (ECons n o). | |
785 Variable OCons_case : forall (n : nat) (e : even_list), Peven e -> Podd (OCons n e). | |
786 | |
787 (** Finally, we define the recursive functions. *) | |
788 Fixpoint even_list_mut' (e : even_list) : Peven e := | |
789 match e return (Peven e) with | |
790 | ENil => ENil_case | |
791 | ECons n o => ECons_case n (odd_list_mut' o) | |
792 end | |
793 with odd_list_mut' (o : odd_list) : Podd o := | |
794 match o return (Podd o) with | |
795 | OCons n e => OCons_case n (even_list_mut' e) | |
796 end. | |
797 End even_list_mut'. | |
798 | |
799 (** Even induction principles for reflexive types are easy to implement directly. For our [formula] type, we can use a recursive definition much like those we wrote above. *) | |
800 | |
801 Section formula_ind'. | |
802 Variable P : formula -> Prop. | |
803 Variable Eq_case : forall n1 n2 : nat, P (Eq n1 n2). | |
804 Variable And_case : forall f1 f2 : formula, | |
805 P f1 -> P f2 -> P (And f1 f2). | |
806 Variable Forall_case : forall f : nat -> formula, | |
807 (forall n : nat, P (f n)) -> P (Forall f). | |
808 | |
809 Fixpoint formula_ind' (f : formula) : P f := | |
810 match f return (P f) with | |
811 | Eq n1 n2 => Eq_case n1 n2 | |
812 | And f1 f2 => And_case (formula_ind' f1) (formula_ind' f2) | |
813 | Forall f' => Forall_case f' (fun n => formula_ind' (f' n)) | |
814 end. | |
815 End formula_ind'. | |
816 |