Mercurial > cpdt > repo
comparison src/Universes.v @ 344:7466ac31f162
New section on avoiding axioms
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Mon, 17 Oct 2011 14:56:46 -0400 |
parents | be8c7aae20f4 |
children | 518c8994a715 |
comparison
equal
deleted
inserted
replaced
343:be8c7aae20f4 | 344:7466ac31f162 |
---|---|
837 : fin (13 + 1) | 837 : fin (13 + 1) |
838 ]] | 838 ]] |
839 | 839 |
840 This simple computational reduction hides the use of a recursive function to produce a suitable [refl_equal] proof term. The recursion originates in our use of [induction] in [t4]'s proof. *) | 840 This simple computational reduction hides the use of a recursive function to produce a suitable [refl_equal] proof term. The recursion originates in our use of [induction] in [t4]'s proof. *) |
841 | 841 |
842 | |
843 (** ** Methods for Avoiding Axioms *) | |
844 | |
845 (** The last section demonstrated one reason to avoid axioms: they interfere with computational behavior of terms. A further reason is to reduce the philosophical commitment of a theorem. The more axioms one assumes, the harder it becomes to convince oneself that the formal system corresponds appropriately to one's intuitions. A refinement of this last point, in applications like %\index{proof-carrying code}%proof-carrying code%~\cite{PCC}% in computer security, has to do with minimizing the size of a %\index{trusted code base}\emph{%#<i>#trusted code base#</i>#%}%. To convince ourselves that a theorem is true, we must convince ourselves of the correctness of the program that checks the theorem. Axioms effectively become new source code for the checking program, increasing the effort required to perform a correctness audit. | |
846 | |
847 An earlier section gave one example of avoiding an axiom. We proved that [pred_strong1] is agnostic to details of the proofs passed to it as arguments, by unfolding the definition of the function. A %``%#"#simpler#"#%''% proof keeps the function definition opaque and instead applies a proof irrelevance axiom. By accepting a more complex proof, we reduce our philosophical commitment and trusted base. (By the way, the less-than relation that the proofs in question here prove turns out to admit proof irrelevance as a theorem provable within normal Gallina!) | |
848 | |
849 One dark secret of the [dep_destruct] tactic that we have used several times is reliance on an axiom. Consider this simple case analysis principle for [fin] values: *) | |
850 | |
851 Theorem fin_cases : forall n (f : fin (S n)), f = First \/ exists f', f = Next f'. | |
852 intros; dep_destruct f; eauto. | |
853 Qed. | |
854 | |
855 Print Assumptions fin_cases. | |
856 (** %\vspace{-.15in}%[[ | |
857 Axioms: | |
858 JMeq.JMeq_eq : forall (A : Type) (x y : A), JMeq.JMeq x y -> x = y | |
859 ]] | |
860 | |
861 The proof depends on the [JMeq_eq] axiom that we met in the chapter on equality proofs. However, a smarter tactic could have avoided an axiom dependence. Here is an alternate proof via a slightly strange looking lemma. *) | |
862 | |
863 (* begin thide *) | |
864 Lemma fin_cases_again' : forall n (f : fin n), | |
865 match n return fin n -> Prop with | |
866 | O => fun _ => False | |
867 | S n' => fun f => f = First \/ exists f', f = Next f' | |
868 end f. | |
869 destruct f; eauto. | |
870 Qed. | |
871 | |
872 (** We apply a variant of the %\index{convoy pattern}%convoy pattern, which we are used to seeing in function implementations. Here, the pattern helps us state a lemma in a form where the argument to [fin] is a variable. Recall that, thanks to basic typing rules for pattern-matching, [destruct] will only work effectively on types whose non-parameter arguments are variables. The %\index{tactics!exact}%[exact] tactic, which takes as argument a literal proof term, now gives us an easy way of proving the original theorem. *) | |
873 | |
874 Theorem fin_cases_again : forall n (f : fin (S n)), f = First \/ exists f', f = Next f'. | |
875 intros; exact (fin_cases_again' f). | |
876 Qed. | |
877 (* end thide *) | |
878 | |
879 Print Assumptions fin_cases_again. | |
880 (** %\vspace{-.15in}% | |
881 << | |
882 Closed under the global context | |
883 >> | |
884 | |
885 As another example, consider the following type of formulas in first-order logic. The intent of the type definition will not be important in what follows, but we give a quick intuition for the curious reader. Our formulas may include [forall] quantification over arbitrary [Type]s, and we index formulas by environments telling which variables are in scope and what their types are; such an environment is a [list Type]. A constructor [Inject] lets us include any Coq [Prop] as a formula, and [VarEq] and [Lift] can be used for variable references, in what is essentially the de Bruijn index convention. (Again, the detail in this paragraph is not important to understand the discussion that follows!) *) | |
886 | |
887 Inductive formula : list Type -> Type := | |
888 | Inject : forall Ts, Prop -> formula Ts | |
889 | VarEq : forall T Ts, T -> formula (T :: Ts) | |
890 | Lift : forall T Ts, formula Ts -> formula (T :: Ts) | |
891 | Forall : forall T Ts, formula (T :: Ts) -> formula Ts | |
892 | And : forall Ts, formula Ts -> formula Ts -> formula Ts. | |
893 | |
894 (** This example is based on my own experiences implementing variants of a program logic called XCAP%~\cite{XCAP}%, which also includes an inductive predicate for characterizing which formulas are provable. Here I include a pared-down version of such a predicate, with only two constructors, which is sufficient to illustrate certain tricky issues. *) | |
895 | |
896 Inductive proof : formula nil -> Prop := | |
897 | PInject : forall (P : Prop), P -> proof (Inject nil P) | |
898 | PAnd : forall p q, proof p -> proof q -> proof (And p q). | |
899 | |
900 (** Let us prove a lemma showing that a %``%#"#[P /\ Q -> P]#"#%''% rule is derivable within the rules of [proof]. *) | |
901 | |
902 Theorem proj1 : forall p q, proof (And p q) -> proof p. | |
903 destruct 1. | |
904 (** %\vspace{-.15in}%[[ | |
905 p : formula nil | |
906 q : formula nil | |
907 P : Prop | |
908 H : P | |
909 ============================ | |
910 proof p | |
911 ]] | |
912 *) | |
913 | |
914 (** We are reminded that [induction] and [destruct] do not work effectively on types with non-variable arguments. The first subgoal, shown above, is clearly unprovable. (Consider the case where [p = Inject nil False].) | |
915 | |
916 An application of the %\index{tactics!dependent destruction}%[dependent destruction] tactic (the basis for [dep_destruct]) solves the problem handily. We use a shorthand with the %\index{tactics!intros}%[intros] tactic that lets us use question marks for variable names that do not matter. *) | |
917 | |
918 Restart. | |
919 Require Import Program. | |
920 intros ? ? H; dependent destruction H; auto. | |
921 Qed. | |
922 | |
923 Print Assumptions proj1. | |
924 (** %\vspace{-.15in}%[[ | |
925 Axioms: | |
926 eq_rect_eq : forall (U : Type) (p : U) (Q : U -> Type) (x : Q p) (h : p = p), | |
927 x = eq_rect p Q x p h | |
928 ]] | |
929 | |
930 Unfortunately, that built-in tactic appeals to an axiom. It is still possible to avoid axioms by giving the proof via another odd-looking lemma. Here is a first attempt that fails at remaining axiom-free, using a common equality-based trick for supporting induction on non-variable arguments to type families. The trick works fine without axioms for datatypes more traditional than [formula], but we run into trouble with our current type. *) | |
931 | |
932 Lemma proj1_again' : forall r, proof r | |
933 -> forall p q, r = And p q -> proof p. | |
934 destruct 1; crush. | |
935 (** %\vspace{-.15in}%[[ | |
936 H0 : Inject [] P = And p q | |
937 ============================ | |
938 proof p | |
939 ]] | |
940 | |
941 The first goal looks reasonable. Hypothesis [H0] is clearly contradictory, as [discriminate] can show. *) | |
942 | |
943 discriminate. | |
944 (** %\vspace{-.15in}%[[ | |
945 H : proof p | |
946 H1 : And p q = And p0 q0 | |
947 ============================ | |
948 proof p0 | |
949 ]] | |
950 | |
951 It looks like we are almost done. Hypothesis [H1] gives [p = p0] by injectivity of constructors, and then [H] finishes the case. *) | |
952 | |
953 injection H1; intros. | |
954 | |
955 (** Unfortunately, the %``%#"#equality#"#%''% that we expected between [p] and [p0] comes in a strange form: | |
956 | |
957 [[ | |
958 H3 : existT (fun Ts : list Type => formula Ts) []%list p = | |
959 existT (fun Ts : list Type => formula Ts) []%list p0 | |
960 ============================ | |
961 proof p0 | |
962 ]] | |
963 | |
964 It may take a bit of tinkering, but, reviewing Chapter 3's discussion of writing injection principles manually, it makes sense that an [existT] type is the most direct way to express the output of [inversion] on a dependently typed constructor. The constructor [And] is dependently typed, since it takes a parameter [Ts] upon which the types of [p] and [q] depend. Let us not dwell further here on why this goal appears; the reader may like to attempt the (impossible) exercise of building a better injection lemma for [And], without using axioms. | |
965 | |
966 How exactly does an axiom come into the picture here? Let us ask [crush] to finish the proof. *) | |
967 | |
968 crush. | |
969 Qed. | |
970 | |
971 Print Assumptions proj1_again'. | |
972 (** %\vspace{-.15in}%[[ | |
973 Axioms: | |
974 eq_rect_eq : forall (U : Type) (p : U) (Q : U -> Type) (x : Q p) (h : p = p), | |
975 x = eq_rect p Q x p h | |
976 ]] | |
977 | |
978 It turns out that this familiar axiom about equality (or some other axiom) is required to deduce [p = p0] from the hypothesis [H3] above. The soundness of that proof step is neither provable nor disprovable in Gallina. | |
979 | |
980 Hope is not lost, however. We can produce an even stranger looking lemma, which gives us the theorem without axioms. *) | |
981 | |
982 Lemma proj1_again'' : forall r, proof r | |
983 -> match r with | |
984 | And Ps p _ => match Ps return formula Ps -> Prop with | |
985 | nil => fun p => proof p | |
986 | _ => fun _ => True | |
987 end p | |
988 | _ => True | |
989 end. | |
990 destruct 1; auto. | |
991 Qed. | |
992 | |
993 Theorem proj1_again : forall p q, proof (And p q) -> proof p. | |
994 intros ? ? H; exact (proj1_again'' H). | |
995 Qed. | |
996 | |
997 Print Assumptions proj1_again. | |
998 (** << | |
999 Closed under the global context | |
1000 >> | |
1001 | |
1002 This example illustrates again how some of the same design patterns we learned for dependently typed programming can be used fruitfully in theorem statements. *) |