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