Require Import logic4. (* Beginning uses of automation *) (* Here's a fairly typical little lemma with quite a bit of repetitive structure. *) Lemma next_even_deterministic : partial_function next_even. Proof. unfold partial_function. intros x y1 y2 P1. induction P1. Case "S x". intros P2. inversion P2. SCase "S x". reflexivity. SCase "SS x". impossible. apply even_not_even_S with (S x). apply H. apply H0. Case "SS x". intros P2. inversion P2. SCase "S x". impossible. apply even_not_even_S with (S x). apply H0. apply H. SCase "SS x". reflexivity. Qed. (* We'll introduce some tactics to make it simpler and more compact. *) (* First off, whenever we want to [apply] a hypothesis exactly, we can just use [assumption] instead, without having to give the precise name of the hypothesis. *) Lemma next_even_deterministic' : partial_function next_even. Proof. unfold partial_function. intros x y1 y2 P1. induction P1. Case "S x". intros P2. inversion P2. SCase "S x". reflexivity. SCase "SS x". impossible. apply even_not_even_S with (S x). assumption. assumption. Case "SS x". intros P2. inversion P2. SCase "S x". impossible. apply even_not_even_S with (S x). assumption. assumption. SCase "SS x". reflexivity. Qed. (* Now we can see that we often do the same thing to all subgoals. We can often avoid this using the so-called "tactical" [t1 ; t2] means: apply tactic t1; then apply tactic t2 to every subgoal generated by t1. *) Lemma next_even_deterministic'' : partial_function next_even. Proof. unfold partial_function. intros x y1 y2 P1. induction P1; intros P2; inversion P2. Case "S x". SCase "S x". reflexivity. SCase "SS x". impossible. apply even_not_even_S with (S x); assumption. Case "SS x". SCase "S x". impossible. apply even_not_even_S with (S x); assumption. SCase "SS x". reflexivity. Qed. (* Note: many people use [;] to connect "related" tactics even when the first generates only one subgoal. I try to avoid this, but it's fairly harmless. For example, we can change [impossible. apply ...] to [impossible; apply...]. This will prove useful later. *) (* There is a very powerful tactic called [auto]. One of its simplest uses is as a shorthand: it works whenever [assumption] or [reflexivity] would work. *) Lemma next_even_deterministic''' : partial_function next_even. Proof. unfold partial_function. intros x y1 y2 P1. induction P1; intros P2; inversion P2. Case "S x". SCase "S x". auto. SCase "SS x". impossible; apply even_not_even_S with (S x); auto. Case "SS x". SCase "S x". impossible; apply even_not_even_S with (S x); auto. SCase "SS x". auto. Qed. (* There's still some arguably annoying repetition in this proof. We can handle it by using the tactical [try solve [t1 | t2 | ... | tn]]. This attempts to solve the goal using t1, t2, ..., tn in turn. *) Lemma next_even_deterministic'''' : partial_function next_even. Proof. unfold partial_function. intros x y1 y2 P1. induction P1; intros P2; inversion P2; try solve [auto | impossible; apply even_not_even_S with (S x); auto]. Qed. (* Reasonable people may disagree about whether this last version is an improvement... *) (* [auto] can do much more than we've seen so far. It really implements a limited form of proof *search*. For example, if we have some conditional hypotheses whose preconditions are also hypotheses, [auto] can often do all the work for us. *) Lemma not_using_auto : forall (P Q R:Prop), (P -> Q) -> (Q -> R) -> (P -> R). Proof. intros P Q R H1 H2 p. apply H2. apply H1. apply p. Qed. Lemma using_auto : forall (P Q R:Prop), (P -> Q) -> (Q -> R) -> (P -> R). Proof. (* intros P Q R H1 H2 p. (* even this is optional *) *) auto. Qed. (* [auto] has a limited "search depth"; sometimes it can't "see far enough ahead". Note that [auto] only works when it can solve the goal completely; otherwise it does nothing at all. *) Lemma using_auto' : forall (P Q R S T U :Prop), (P -> Q) -> (Q -> R) -> (R -> S) -> (S -> T) -> (T -> U) -> (P -> U). Proof. intros P Q R S T U H1 H2 H3 H4 H5 p. auto. apply H5. auto. Qed. (* In still more advanced form, [auto] can use a database of "hints" that tell it about lemmas it should try to use. ... *) (* ---------------------------------- *) (* The midterm will use the following Proposition, describing the membership of a value in a list of values. This is a slighly new kind of Prop definition: it is defined using [Fixpoint] rather than [Definition] or [Inductive]. As usual, a value of the form (In x xs) represents *evidence* that [x] is equal to someting in the list [xs]. *) Fixpoint In (A:Set) (a:A) (l:list A) {struct l} : Prop := match l with | nil => False | b :: m => b = a \/ In _ a m end. Implicit Arguments In [A]. (* Here's a simple Lemma about In, which illustrates how to reason about this proposition. *) Lemma In_not_head : forall (A:Set) (x:A) y ys, In x (y::ys) -> x <> y -> In x ys. Proof. intros A x y ys P NE. simpl in P. inversion P. Case "y = x". rewrite H in NE. impossible. apply NE. reflexivity. Case "In x ys". assumption. Qed. (* Let's do this proof again, using some shortcuts and also introduceing a couple of new tactics: - The [subst] tactic automatically [rewrite]s everywhere all simple identifiers that appear among the hypotheses. It is particularly handy immediately after [inversion], which often generates lots of equalities. - The [fold] tactic is the inverse of [unfold]; it is useful when Coq decides to unfold something (especially something recursive) that you would rather keep abstract. Its primary use is just for readability. *) Lemma In_not_head' : forall (A:Set) (x:A) y ys, In x (y::ys) -> x <> y -> In x ys. Proof. intros A x y ys P NE. inversion P. (* inversion will do the simpl automatically *) Case "y = x". subst. (* this does the rewrite of H in NE -- and in P -- automatically. *) impossible. auto. (* auto finds and applies NE and then applies reflexivity. *) Case "In x ys". fold In in H. (* this is purely cosmetic, but it can be helpful! *) auto. Qed.