(** * Software Foundations, Formally Benjamin C. Pierce Version of 9/26/2007 *) Require Export lec06_sol. (* LECTURE 7 *) (* ====================================================================== *) (* Logical connectives as inductively defined propositions *) (* Like its built-in programming language, Coq's built-in logic is extremely small: universal quantification ([forall]) and implication ([->]) are primitive, but all the other familiar logical connectives (conjunction, disjunction, negation, and existential quantification) can be defined using just these together with [Inductive]. *) (* ---------------------------------------------------------------------- *) (* Conjunction *) (* The logical conjunction of propositions [A] and [B] is represented by the following inductively defined proposition. *) Inductive and (A B : Prop) : Prop := conj : A -> B -> (and A B). (* Intuition: To construct evidence for [and A B], we simply provide evidence for [A] and evidence for [B]. More precisely: - [conj e1 e2] can be taken as evidence for [and A B] if [e1] is evidence for [A] and [e2] is evidence for [B]; and - this is the ONLY way to give evidence for [and A B] -- that is, if someone gives us evidence for [and A B], we know it must have the form [conj e1 e2], where [e1] is evidence for [A] and [e2] is evidence for [B]. *) (* More familiar syntax: *) Notation "A /\ B" := (and A B) : type_scope. (* THOUGHT EXERCISE: See if you can predict the induction principle for conjunction. *) Check and_ind. (* What's nice about defining conjunction in this way is that we can prove statements involving conjunction using the tactics that we already know. For example, if the goal statement is a conjuction, we can prove it ("backward") by applying the single constructor [conj], which (as can be seen from the type of [conj]) solves the current goal and leaves the two parts of the conjunction as subgoals to be proved separately. *) Lemma and_example : (evenI zero) /\ (evenI four). Proof. apply conj. Case "left". apply even_zero. Case "right". apply even_SS. apply even_SS. apply even_zero. Qed. (* Conversely, the [inversion] tactic can be used to investigate a conjunction hypothesis in the context and calculate what evidence must have been used to build it. *) Lemma and_1 : forall A B : Prop, A /\ B -> A. Proof. intros A B H. (* Wei: or [destruct H] *) inversion H. apply H0. Qed. (* In general, the [inversion] tactic - takes a hypothesis H whose type is some inductively defined proposition A - for each constructor C in A's definition - generates a new subgoal in which we assume H was built with C - adds the arguments (premises) of C to the context of the subgoal as extra hypotheses - matches the conclusion (result type) of C against the current goal and calculates a set of equalities that must hold in order for C to be applicable - adds these equalities to the context of the subgoal - if the equalities are not satisfiable (e.g., they involve things like [S n = O], immediately solves the subgoal. (This may look a bit different from the way we used [inversion] in earlier lectures, to extract additional equalities from an equality hypothesis by using the facts that the constructors of an inductive type are disjoint and injective. But the fundamental mechanism is exactly the same.) In the case of [and], there is only one constructor, so only one subgoal gets generated. And the conclusion (result type) of the constructor -- [A /\ B] -- doesn't place any restrictions on the form of A and B, so we don't get any extra equalities in the context of the subgoal. The constructor does have two arguments, though, and these can be seen in the context in the subgoal. *) Lemma and_2 : forall A B : Prop, A /\ B -> B. Proof. (* Wei: [destruct 1] will [intros until] the [1]-th non-dependent product, and then do a [destruct] *) destruct 1. trivial. Qed. Lemma and_commut : forall A B : Prop, A /\ B -> B /\ A. Proof. intros A B H. apply conj. Case "left". apply and_2 with (A:=A). apply H. Case "right". apply and_1 with (B:=B). apply H. Qed. Lemma and_assoc : forall A B C : Prop, A /\ (B /\ C) -> (A /\ B) /\ C. Proof. destruct 1. destruct H0. (* Wei: instead of [apply conj], we let coq find a constructor for us *) constructor; trivial; try constructor; trivial. Qed. (* Now we are in a position to prove the other direction of the equivalence of [evenE] and [evenI]. Notice that the left-hand conjunct here is the statement we are actually interested in; the right-hand conjunct is needed in order to make the induction hypothesis strong enough that we can carry out the reasoning in the inductive step. (To see why this is needed, try proving the left conjunct by itself and observe where things get stuck.) *) Lemma evenE_evenI : forall n : nat, (evenE n -> evenI n) /\ (evenE (S n) -> evenI (S n)). Proof. (* Hint: Use induction on [n]. *) induction n. (* prove left and right for zero *) constructor. constructor. inversion 1. (* prove left and right for (S n) *) constructor. (* left *) eapply and_2. apply IHn. (* right *) intros. constructor. assert (evenE n). inversion H. unfold evenE. trivial. apply and_1 in IHn. apply (IHn H0). Qed. (* ---------------------------------------------------------------------- *) (* Iff *) (* The familiar logical "iff" is just the conjunction of two implications. *) Definition iff (A B : Prop) := (A -> B) /\ (B -> A). Notation "A <-> B" := (iff A B) : type_scope. Lemma iff_implies : forall A B : Prop, (A <-> B) -> A -> B. Proof. intros A B H. inversion H. apply H0. Qed. Theorem iff_sym : forall A B : Prop, (A <-> B) -> (B <-> A). Proof. intros A B H. inversion H. (* Note that we need [unfold] before we can use [apply conj]. *) unfold iff. apply conj. Case "left". apply H1. Case "right". apply H0. Qed. Theorem iff_refl : forall A : Prop, A <-> A. Proof. intros. constructor; trivial. Qed. Theorem iff_trans : forall A B C : Prop, (A <-> B) -> (B <-> C) -> (A <-> C). Proof. (* Hint: If you have an iff hypothesis in the context, you can use [inversion] to break it into two separate implications. (Think about why this works.) *) intros. destruct H. destruct H0. constructor. intros. apply (H0 (H H3)). intros. apply (H1 (H2 H3)). Qed. (* ---------------------------------------------------------------------- *) (* Disjunction *) (* Disjunction ("logical or") can also be defined as an inductive proposition. *) Inductive or (A B : Prop) : Prop := | or_introl : A -> or A B | or_intror : B -> or A B. Notation "A \/ B" := (or A B) : type_scope. (* Intuition: There are two ways of giving evidence for [A \/ B]: - give evidence for [A] (and say that it is [A] you are giving evidence for! -- this is the function of the [or_introl] constructor) - give evidence for [B], tagged with the [or_intror] constructor. *) (* Thought exercise: See if you can predict the induction principle for disjunction. *) Check or_ind. (* Since [A \/ B] has two constructors, doing [inversion] on a hypothesis of type [A \/ B] yields two subgoals. *) Lemma or_commut : forall A B : Prop, A \/ B -> B \/ A. Proof. intros A B H. inversion H. Case "left". apply or_intror. apply H0. Case "right". apply or_introl. apply H0. Qed. Lemma or_distributes_over_and : forall A B C : Prop, A \/ (B /\ C) <-> (A \/ B) /\ (A \/ C). Proof. constructor. constructor; destruct H. apply or_introl. trivial. apply or_intror. eapply and_1. apply H. apply or_introl. trivial. apply or_intror. eapply and_2. apply H. (* the other direction *) destruct 1. destruct H; destruct H0. apply or_introl; trivial. apply or_introl. trivial. apply or_introl. trivial. apply or_intror. constructor; trivial. Qed. (* ---------------------------------------------------------------------- *) (* Falsehood *) (* [False] is an inductively defined proposition with no constructors! *) Inductive False : Prop := . (* Intuition: [False] is a proposition for which there is no way to give evidence. *) (* THOUGHT EXERCISE: Can you predict the induction principle for falsehood? *) Check False_ind. Lemma False_implies_nonsense : False -> plus two two = five. Proof. intros contra. inversion contra. Qed. (* It *is* sometimes possible to prove the goal [False], but only if the context contains a contradiction (i.e., if the context allows us to prove anything at all). *) Lemma nonsense_implies_False : plus two two = five -> False. Proof. intros contra. inversion contra. Qed. (* ---------------------------------------------------------------------- *) (* Negation *) (* [not A], written [~A], is the logical negation of [A] *) Definition not (A:Prop) := A -> False. Notation "~ x" := (not x) : type_scope. (* Intuition: If we could prove [A], then we could prove [False] (and hence we could prove anything at all). *) Lemma not_False : ~ False. Proof. unfold not. intros H. inversion H. Qed. Lemma contradiction : forall A B : Prop, (A /\ ~A) -> B. Proof. intros A B H. inversion H. (* Wei: We now have both A and ~A, so we can do [absurd A] to prove anything *) unfold not in H1. apply H1 in H0. inversion H0. Qed. Lemma double_neg : forall A : Prop, A -> ~~A. Proof. intros A H. unfold not. intros G. apply G. apply H. Qed. Lemma contrapositive : forall A B : Prop, (A -> B) -> (~B -> ~A). Proof. unfold not in *. intros. exact (H0 (H H1)). Qed. Lemma not_both_true_and_false : forall A : Prop, ~ (A /\ ~A). Proof. unfold not. intros. destruct H. exact (H0 H). Qed. Lemma five_not_even : ~ evenI five. Proof. unfold not. intros H. inversion H. inversion H1. inversion H3. Qed. Lemma even_not_even_S : forall n, evenI n -> ~ evenI (S n). Proof. unfold not. intros n H. induction H. (* not n! *) inversion 1. inversion 1. exact (IHevenI H2). Qed. (* LATER: CoqArt p. 120 has some amusing exercises. Also exercise 5.7, which might be nice for PhD students. *) (* ---------------------------------------------------------------------- *) (* Inequality *) (* Saying [x <> y] is just the same as saying [~ (x = y)]. *) Notation "x <> y" := (~ (x = y)) : type_scope. Lemma Sn_neq_n : forall n : nat, eqnat (S n) n <> yes. Proof. intros n. induction n. simpl. unfold not. intros H. inversion H. unfold not. intros H. unfold not in IHn. apply IHn. apply H. Qed. Lemma not_no_then_yes : forall b : yesno, b <> no -> b = yes. Proof. intros b H. destruct b. Case "O". reflexivity. Case "S". unfold not in H. assert False as contra. Case "Proof of assertion". apply H. reflexivity. inversion contra. Qed. Lemma eqnat_no : forall m n, eqnat m n = no -> m <> n. Proof. unfold not; intros. (* [subst] seeks to [rewrite] anything possible and then cut redundant premises *) subst. assert (forall m, eqnat m m = yes). induction m; simpl; trivial. rewrite H0 with (m:=n) in H. inversion H. Qed.