AltAutoA Streamlined Treatment of Automation
- Tacticals
- Tactics that obviate hardcoded names
- Automatic solvers
- Proof search with auto
- Ltac
Set Warnings "-notation-overridden,-parsing,-deprecated-hint-without-locality".
From Coq Require Import Arith List.
From LF Require Import IndProp.
From Coq Require Import Arith List.
From LF Require Import IndProp.
Fixpoint re_opt_e {T:Type} (re: reg_exp T) : reg_exp T :=
match re with
| App EmptyStr re2 ⇒ re_opt_e re2
| App re1 re2 ⇒ App (re_opt_e re1) (re_opt_e re2)
| Union re1 re2 ⇒ Union (re_opt_e re1) (re_opt_e re2)
| Star re ⇒ Star (re_opt_e re)
| _ ⇒ re
end.
match re with
| App EmptyStr re2 ⇒ re_opt_e re2
| App re1 re2 ⇒ App (re_opt_e re1) (re_opt_e re2)
| Union re1 re2 ⇒ Union (re_opt_e re1) (re_opt_e re2)
| Star re ⇒ Star (re_opt_e re)
| _ ⇒ re
end.
We would like to show the equivalence of re's with their
"optimized" form. One direction of this equivalence looks like
this (the other is similar).
Lemma re_opt_e_match : ∀ T (re: reg_exp T) s,
s =~ re → s =~ re_opt_e re.
Proof.
intros T re s M.
induction M
as [| x'
| s1 re1 s2 re2 Hmatch1 IH1 Hmatch2 IH2
| s1 re1 re2 Hmatch IH | re1 s2 re2 Hmatch IH
| re | s1 s2 re Hmatch1 IH1 Hmatch2 IH2].
- (* MEmpty *) simpl. apply MEmpty.
- (* MChar *) simpl. apply MChar.
- (* MApp *) simpl.
destruct re1.
+ apply MApp.
× apply IH1.
× apply IH2.
+ inversion Hmatch1. simpl. apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
- (* MUnionL *) simpl. apply MUnionL. apply IH.
- (* MUnionR *) simpl. apply MUnionR. apply IH.
- (* MStar0 *) simpl. apply MStar0.
- (* MStarApp *) simpl. apply MStarApp.
× apply IH1.
× apply IH2.
Qed.
s =~ re → s =~ re_opt_e re.
Proof.
intros T re s M.
induction M
as [| x'
| s1 re1 s2 re2 Hmatch1 IH1 Hmatch2 IH2
| s1 re1 re2 Hmatch IH | re1 s2 re2 Hmatch IH
| re | s1 s2 re Hmatch1 IH1 Hmatch2 IH2].
- (* MEmpty *) simpl. apply MEmpty.
- (* MChar *) simpl. apply MChar.
- (* MApp *) simpl.
destruct re1.
+ apply MApp.
× apply IH1.
× apply IH2.
+ inversion Hmatch1. simpl. apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
+ apply MApp.
× apply IH1.
× apply IH2.
- (* MUnionL *) simpl. apply MUnionL. apply IH.
- (* MUnionR *) simpl. apply MUnionR. apply IH.
- (* MStar0 *) simpl. apply MStar0.
- (* MStarApp *) simpl. apply MStarApp.
× apply IH1.
× apply IH2.
Qed.
That last proof was getting a little repetitive. Time to
learn a few more Coq tricks...
Tacticals
The try Tactical
Theorem silly1 : ∀ n, 1 + n = S n.
Proof. try reflexivity. (* this just does reflexivity *) Qed.
Theorem silly2 : ∀ (P : Prop), P → P.
Proof.
intros P HP.
Fail reflexivity.
try reflexivity. (* proof state is unchanged *)
apply HP.
Qed.
Proof. try reflexivity. (* this just does reflexivity *) Qed.
Theorem silly2 : ∀ (P : Prop), P → P.
Proof.
intros P HP.
Fail reflexivity.
try reflexivity. (* proof state is unchanged *)
apply HP.
Qed.
The Sequence Tactical ; (Simple Form)
Lemma simple_semi : ∀ n, (n + 1 =? 0) = false.
Proof.
intros n.
destruct n eqn:E.
(* Leaves two subgoals, which are discharged identically... *)
- (* n=0 *) simpl. reflexivity.
- (* n=Sn' *) simpl. reflexivity.
Qed.
Proof.
intros n.
destruct n eqn:E.
(* Leaves two subgoals, which are discharged identically... *)
- (* n=0 *) simpl. reflexivity.
- (* n=Sn' *) simpl. reflexivity.
Qed.
Lemma simple_semi' : ∀ n, (n + 1 =? 0) = false.
Proof.
intros n.
(* destruct the current goal *)
destruct n;
(* then simpl each resulting subgoal *)
simpl;
(* and do reflexivity on each resulting subgoal *)
reflexivity.
Qed.
Proof.
intros n.
(* destruct the current goal *)
destruct n;
(* then simpl each resulting subgoal *)
simpl;
(* and do reflexivity on each resulting subgoal *)
reflexivity.
Qed.
Lemma simple_semi'' : ∀ n, (n + 1 =? 0) = false.
Proof.
destruct n; reflexivity.
Qed.
Proof.
destruct n; reflexivity.
Qed.
Lemma re_opt_e_match' : ∀ T (re: reg_exp T) s,
s =~ re → s =~ re_opt_e re.
Proof.
intros T re s M.
induction M
as [| x'
| s1 re1 s2 re2 Hmatch1 IH1 Hmatch2 IH2
| s1 re1 re2 Hmatch IH | re1 s2 re2 Hmatch IH
| re | s1 s2 re Hmatch1 IH1 Hmatch2 IH2];
(* Do the simpl for every case here: *)
simpl.
- (* MEmpty *) apply MEmpty.
- (* MChar *) apply MChar.
- (* MApp *)
destruct re1;
(* Most cases follow by the same formula. Notice that apply MApp gives two subgoals: try apply IH1 is run on _both_ of
them and succeeds on the first but not the second; apply IH2
is then run on this remaining goal. *)
try (apply MApp; try apply IH1; apply IH2).
(* The interesting case, on which try... does nothing, is when
re1 = EmptyStr. In this case, we have to appeal to the fact
that re1 matches only the empty string: *)
inversion Hmatch1. simpl. apply IH2.
- (* MUnionL *) apply MUnionL. apply IH.
- (* MUnionR *) apply MUnionR. apply IH.
- (* MStar0 *) apply MStar0.
- (* MStarApp *) apply MStarApp. apply IH1. apply IH2.
Qed.
s =~ re → s =~ re_opt_e re.
Proof.
intros T re s M.
induction M
as [| x'
| s1 re1 s2 re2 Hmatch1 IH1 Hmatch2 IH2
| s1 re1 re2 Hmatch IH | re1 s2 re2 Hmatch IH
| re | s1 s2 re Hmatch1 IH1 Hmatch2 IH2];
(* Do the simpl for every case here: *)
simpl.
- (* MEmpty *) apply MEmpty.
- (* MChar *) apply MChar.
- (* MApp *)
destruct re1;
(* Most cases follow by the same formula. Notice that apply MApp gives two subgoals: try apply IH1 is run on _both_ of
them and succeeds on the first but not the second; apply IH2
is then run on this remaining goal. *)
try (apply MApp; try apply IH1; apply IH2).
(* The interesting case, on which try... does nothing, is when
re1 = EmptyStr. In this case, we have to appeal to the fact
that re1 matches only the empty string: *)
inversion Hmatch1. simpl. apply IH2.
- (* MUnionL *) apply MUnionL. apply IH.
- (* MUnionR *) apply MUnionR. apply IH.
- (* MStar0 *) apply MStar0.
- (* MStarApp *) apply MStarApp. apply IH1. apply IH2.
Qed.
Theorem In10 : In 10 [1;2;3;4;5;6;7;8;9;10].
Proof.
repeat (try (left; reflexivity); right).
Qed.
Proof.
repeat (try (left; reflexivity); right).
Qed.
Theorem hyp_name : ∀ (P : Prop), P → P.
Proof.
intros P HP. apply HP.
Qed.
Proof.
intros P HP. apply HP.
Qed.
Theorem no_hyp_name : ∀ (P : Prop), P → P.
Proof.
intros. assumption.
Qed.
Proof.
intros. assumption.
Qed.
There's a tradeoff between ease of reading and ease of
writing/maintaining. Eliminating hardcoded names can help with
both.
The contradiction tactic
Theorem false_assumed : False → 0 = 1.
Proof.
intros H. destruct H.
Qed.
Theorem false_assumed' : False → 0 = 1.
Proof.
intros. contradiction.
Qed.
Theorem contras : ∀ (P : Prop), P → ¬P → 0 = 1.
Proof.
intros P HP HNP. exfalso. apply HNP. apply HP.
Qed.
Theorem contras' : ∀ (P : Prop), P → ¬P → 0 = 1.
Proof.
intros. contradiction.
Qed.
Proof.
intros H. destruct H.
Qed.
Theorem false_assumed' : False → 0 = 1.
Proof.
intros. contradiction.
Qed.
Theorem contras : ∀ (P : Prop), P → ¬P → 0 = 1.
Proof.
intros P HP HNP. exfalso. apply HNP. apply HP.
Qed.
Theorem contras' : ∀ (P : Prop), P → ¬P → 0 = 1.
Proof.
intros. contradiction.
Qed.
The subst tactic
Theorem many_eq : ∀ (n m o p : nat),
n = m →
o = p →
[n; o] = [m; p].
Proof.
intros n m o p Hnm Hop. rewrite Hnm. rewrite Hop. reflexivity.
Qed.
Theorem many_eq' : ∀ (n m o p : nat),
n = m →
o = p →
[n; o] = [m; p].
Proof.
intros. subst. reflexivity.
Qed.
n = m →
o = p →
[n; o] = [m; p].
Proof.
intros n m o p Hnm Hop. rewrite Hnm. rewrite Hop. reflexivity.
Qed.
Theorem many_eq' : ∀ (n m o p : nat),
n = m →
o = p →
[n; o] = [m; p].
Proof.
intros. subst. reflexivity.
Qed.
Example constructor_example: ∀ (n:nat),
ev (n + n).
Proof.
induction n; simpl.
- constructor. (* applies ev_0 *)
- rewrite add_comm. simpl. constructor. (* applies ev_SS *)
assumption.
Qed.
ev (n + n).
Proof.
induction n; simpl.
- constructor. (* applies ev_0 *)
- rewrite add_comm. simpl. constructor. (* applies ev_SS *)
assumption.
Qed.
Automatic Solvers
Linear Integer Arithmetic: The lia Tactic
From Coq Require Import Lia.
Theorem lia_succeed1 : ∀ (n : nat),
n > 0 → n × 2 > n.
Proof. lia. Qed.
Theorem lia_succeed2 : ∀ (n m : nat),
n × m = m × n.
Proof.
lia. (* solvable though non-linear *)
Qed.
Theorem lia_fail1 : 0 = 1.
Proof.
Fail lia. (* goal is invalid *)
Abort.
Theorem lia_fail2 : ∀ (n : nat),
n ≥ 1 → 2 ^ n = 2 × 2 ^ (n - 1).
Proof.
Fail lia. (*goal is non-linear, valid, but unsolvable by lia *)
Abort.
Theorem lia_succeed1 : ∀ (n : nat),
n > 0 → n × 2 > n.
Proof. lia. Qed.
Theorem lia_succeed2 : ∀ (n m : nat),
n × m = m × n.
Proof.
lia. (* solvable though non-linear *)
Qed.
Theorem lia_fail1 : 0 = 1.
Proof.
Fail lia. (* goal is invalid *)
Abort.
Theorem lia_fail2 : ∀ (n : nat),
n ≥ 1 → 2 ^ n = 2 × 2 ^ (n - 1).
Proof.
Fail lia. (*goal is non-linear, valid, but unsolvable by lia *)
Abort.
Equalities: The congruence Tactic
Theorem eq_example1 :
∀ (A B C : Type) (f : A → B) (g : B → C) (x : A) (y : B),
y = f x → g y = g (f x).
Proof.
intros. rewrite H. reflexivity.
Qed.
∀ (A B C : Type) (f : A → B) (g : B → C) (x : A) (y : B),
y = f x → g y = g (f x).
Proof.
intros. rewrite H. reflexivity.
Qed.
The essential properties of equality are that it is:
- reflexive
- symmetric
- transitive
- a congruence: it respects function and predicate application.
The congruence tactic is a decision procedure for equality with uninterpreted functions and other symbols.
Theorem eq_example1' :
∀ (A B C : Type) (f : A → B) (g : B → C) (x : A) (y : B),
y = f x → g y = g (f x).
Proof.
congruence.
Qed.
Theorem eq_example2 : ∀ (n m o p : nat),
n = m →
o = p →
(n, o) = (m, p).
Proof.
congruence.
Qed.
Theorem eq_example3 : ∀ (X : Type) (h : X) (t : list X),
[] ≠ h :: t.
Proof.
congruence.
Qed.
∀ (A B C : Type) (f : A → B) (g : B → C) (x : A) (y : B),
y = f x → g y = g (f x).
Proof.
congruence.
Qed.
Theorem eq_example2 : ∀ (n m o p : nat),
n = m →
o = p →
(n, o) = (m, p).
Proof.
congruence.
Qed.
Theorem eq_example3 : ∀ (X : Type) (h : X) (t : list X),
[] ≠ h :: t.
Proof.
congruence.
Qed.
Propositions: The intuition Tactic
Theorem intuition_succeed1 : ∀ (P : Prop),
P → P.
Proof. intuition. Qed.
Theorem intuition_succeed2 : ∀ (P Q : Prop),
¬(P ∨ Q) → ¬P ∧ ¬Q.
Proof. intuition. Qed.
Theorem intuition_simplify1 : ∀ (P : Prop),
~~P → P.
Proof.
intuition. (* not a constructively valid formula *)
Abort.
Theorem intuition_simplify2 : ∀ (x y : nat) (P Q : nat → Prop),
x = y ∧ (P x → Q x) ∧ P x → Q y.
Proof.
Fail congruence. (* the propositions stump it *)
intuition. (* the = stumps it, but it simplifies the propositions *)
congruence.
Qed.
P → P.
Proof. intuition. Qed.
Theorem intuition_succeed2 : ∀ (P Q : Prop),
¬(P ∨ Q) → ¬P ∧ ¬Q.
Proof. intuition. Qed.
Theorem intuition_simplify1 : ∀ (P : Prop),
~~P → P.
Proof.
intuition. (* not a constructively valid formula *)
Abort.
Theorem intuition_simplify2 : ∀ (x y : nat) (P Q : nat → Prop),
x = y ∧ (P x → Q x) ∧ P x → Q y.
Proof.
Fail congruence. (* the propositions stump it *)
intuition. (* the = stumps it, but it simplifies the propositions *)
congruence.
Qed.
intuition takes an optional argument.
Theorem intuition_simplify2' : ∀ (x y : nat) (P Q : nat → Prop),
x = y ∧ (P x → Q x) ∧ P x → Q y.
Proof.
intuition congruence.
Qed.
x = y ∧ (P x → Q x) ∧ P x → Q y.
Proof.
intuition congruence.
Qed.
Search Tactics
The auto Tactic
Example auto_example_1 : ∀ (P Q R: Prop),
(P → Q) → (Q → R) → P → R.
Proof.
intros P Q R H1 H2 H3.
apply H2. apply H1. apply H3.
Qed.
(P → Q) → (Q → R) → P → R.
Proof.
intros P Q R H1 H2 H3.
apply H2. apply H1. apply H3.
Qed.
The auto tactic frees us from this drudgery by searching for a
sequence of applications that will prove the goal:
Example auto_example_1' : ∀ (P Q R: Prop),
(P → Q) → (Q → R) → P → R.
Proof.
auto.
Qed.
(P → Q) → (Q → R) → P → R.
Proof.
auto.
Qed.
The auto tactic solves goals that are solvable by any combination of
- intros and
- apply (of hypotheses from the local context, by default).
Example auto_example_2 : ∀ P Q R S T U : Prop,
(P → Q) →
(P → R) →
(T → R) →
(S → T → U) →
((P → Q) → (P → S)) →
T →
P →
U.
Proof. auto. Qed.
(P → Q) →
(P → R) →
(T → R) →
(S → T → U) →
((P → Q) → (P → S)) →
T →
P →
U.
Proof. auto. Qed.
Proof search could, in principle, take an arbitrarily long time, so there are limits to how far auto will search by default.
Example auto_example_3 : ∀ (P Q R S T U: Prop),
(P → Q) →
(Q → R) →
(R → S) →
(S → T) →
(T → U) →
P →
U.
Proof.
(* When it cannot solve the goal, auto does nothing *)
auto.
(* Optional argument says how deep to search (default is 5) *)
auto 6.
Qed.
(P → Q) →
(Q → R) →
(R → S) →
(S → T) →
(T → U) →
P →
U.
Proof.
(* When it cannot solve the goal, auto does nothing *)
auto.
(* Optional argument says how deep to search (default is 5) *)
auto 6.
Qed.
Example auto_example_4 : ∀ P Q R : Prop,
Q →
(Q → R) →
P ∨ (Q ∧ R).
Proof. auto. Qed.
Q →
(Q → R) →
P ∨ (Q ∧ R).
Proof. auto. Qed.
If we want to see which facts auto is using, we can use
info_auto instead.
Example auto_example_5 : 2 = 2.
Proof.
(* auto subsumes reflexivity because eq_refl is in the hint
database. *)
info_auto.
Qed.
Proof.
(* auto subsumes reflexivity because eq_refl is in the hint
database. *)
info_auto.
Qed.
We can extend the hint database with theorem t just for the purposes of one application of auto by writing auto using t.
Lemma le_antisym : ∀ n m: nat, (n ≤ m ∧ m ≤ n) → n = m.
Proof. intros. lia. Qed.
Example auto_example_6 : ∀ n m p : nat,
(n ≤ p → (n ≤ m ∧ m ≤ n)) →
n ≤ p →
n = m.
Proof.
auto using le_antisym.
Qed.
Proof. intros. lia. Qed.
Example auto_example_6 : ∀ n m p : nat,
(n ≤ p → (n ≤ m ∧ m ≤ n)) →
n ≤ p →
n = m.
Proof.
auto using le_antisym.
Qed.
- Hint Resolve T : db.
- Hint Constructors c : db.
- Hint Unfold d : db.
Create HintDb le_db.
Hint Resolve le_antisym : le_db.
Example auto_example_6' : ∀ n m p : nat,
(n ≤ p → (n ≤ m ∧ m ≤ n)) →
n ≤ p →
n = m.
Proof.
auto with le_db.
Qed.
Hint Resolve le_antisym : le_db.
Example auto_example_6' : ∀ n m p : nat,
(n ≤ p → (n ≤ m ∧ m ≤ n)) →
n ≤ p →
n = m.
Proof.
auto with le_db.
Qed.
Example trans_example1: ∀ a b c d,
a ≤ b + b × c →
(1 + c) × b ≤ d →
a ≤ d.
Proof.
intros a b c d H1 H2.
apply le_trans with (b + b × c).
(* ^ We must supply the intermediate value *)
- apply H1.
- simpl in H2. rewrite mul_comm. apply H2.
Qed.
a ≤ b + b × c →
(1 + c) × b ≤ d →
a ≤ d.
Proof.
intros a b c d H1 H2.
apply le_trans with (b + b × c).
(* ^ We must supply the intermediate value *)
- apply H1.
- simpl in H2. rewrite mul_comm. apply H2.
Qed.
apply fails if we leave out the with, even though the
appropriate value for n will become obvious in the very next
step.
With eapply, we can eliminate this silliness:
Example trans_example1': ∀ a b c d,
a ≤ b + b × c →
(1 + c) × b ≤ d →
a ≤ d.
Proof.
intros a b c d H1 H2.
eapply le_trans. (* 1 *)
- apply H1. (* 2 *)
- simpl in H2. rewrite mul_comm. apply H2.
Qed.
a ≤ b + b × c →
(1 + c) × b ≤ d →
a ≤ d.
Proof.
intros a b c d H1 H2.
eapply le_trans. (* 1 *)
- apply H1. (* 2 *)
- simpl in H2. rewrite mul_comm. apply H2.
Qed.
Example trans_example2: ∀ a b c d,
a ≤ b + b × c →
b + b × c ≤ d →
a ≤ d.
Proof.
intros a b c d H1 H2.
info_eauto using le_trans.
Qed.
a ≤ b + b × c →
b + b × c ≤ d →
a ≤ d.
Proof.
intros a b c d H1 H2.
info_eauto using le_trans.
Qed.
eauto is significantly slower than auto. Use only as
needed.
Ltac: The Tactic Language
- OCaml: low-level implementation (for wizards)
- Ltac: in-Coq language (for everyone)
Ltac Functions
Ltac simpl_and_try tac := simpl; try tac.
Example sat_ex1 : 1 + 1 = 2.
Proof. simpl_and_try reflexivity. Qed.
Example sat_ex2 : ∀ (n : nat), 1 - 1 + n + 1 = 1 + n.
Proof. simpl_and_try reflexivity. lia. Qed.
Example sat_ex1 : 1 + 1 = 2.
Proof. simpl_and_try reflexivity. Qed.
Example sat_ex2 : ∀ (n : nat), 1 - 1 + n + 1 = 1 + n.
Proof. simpl_and_try reflexivity. lia. Qed.
Theorem plus_1_neq_0 : ∀ n : nat,
(n + 1) =? 0 = false.
Proof.
intros n. destruct n.
- reflexivity.
- reflexivity.
Qed.
Theorem negb_involutive : ∀ b : bool,
negb (negb b) = b.
Proof.
intros b. destruct b.
- reflexivity.
- reflexivity.
Qed.
Theorem andb_commutative : ∀ b c, andb b c = andb c b.
Proof.
intros b c. destruct b.
- destruct c.
+ reflexivity.
+ reflexivity.
- destruct c.
+ reflexivity.
+ reflexivity.
Qed.
(n + 1) =? 0 = false.
Proof.
intros n. destruct n.
- reflexivity.
- reflexivity.
Qed.
Theorem negb_involutive : ∀ b : bool,
negb (negb b) = b.
Proof.
intros b. destruct b.
- reflexivity.
- reflexivity.
Qed.
Theorem andb_commutative : ∀ b c, andb b c = andb c b.
Proof.
intros b c. destruct b.
- destruct c.
+ reflexivity.
+ reflexivity.
- destruct c.
+ reflexivity.
+ reflexivity.
Qed.
We can factor out the common structure:
- Do a destruct.
- For each branch, finish with reflexivity -- if possible.
Ltac destructpf x :=
destruct x; try reflexivity.
Theorem plus_1_neq_0' : ∀ n : nat,
(n + 1) =? 0 = false.
Proof. intros n; destructpf n. Qed.
Theorem negb_involutive' : ∀ b : bool,
negb (negb b) = b.
Proof. intros b; destructpf b. Qed.
Theorem andb_commutative' : ∀ b c, andb b c = andb c b.
Proof.
intros b c; destructpf b; destructpf c.
Qed.
destruct x; try reflexivity.
Theorem plus_1_neq_0' : ∀ n : nat,
(n + 1) =? 0 = false.
Proof. intros n; destructpf n. Qed.
Theorem negb_involutive' : ∀ b : bool,
negb (negb b) = b.
Proof. intros b; destructpf b. Qed.
Theorem andb_commutative' : ∀ b c, andb b c = andb c b.
Proof.
intros b c; destructpf b; destructpf c.
Qed.
Ltac Pattern Matching
Here is another common proof pattern that we have seen in many simple proofs by induction:
Theorem app_nil_r : ∀ (X : Type) (lst : list X),
lst ++ [] = lst.
Proof.
intros X lst. induction lst as [ | h t IHt].
- reflexivity.
- simpl. rewrite IHt. reflexivity.
Qed.
lst ++ [] = lst.
Proof.
intros X lst. induction lst as [ | h t IHt].
- reflexivity.
- simpl. rewrite IHt. reflexivity.
Qed.
Theorem match_ex1 : True.
Proof.
match goal with
| [ ⊢ True ] ⇒ apply I
end.
Qed.
Proof.
match goal with
| [ ⊢ True ] ⇒ apply I
end.
Qed.
That says: if the conclusion is True (regardless of the
hypotheses), run apply I.
There may be multiple branches, which are tried in order.
Theorem match_ex2 : True ∧ True.
Proof.
match goal with
| [ ⊢ True ] ⇒ apply I
| [ ⊢ True ∧ True ] ⇒ split; apply I
end.
Qed.
Proof.
match goal with
| [ ⊢ True ] ⇒ apply I
| [ ⊢ True ∧ True ] ⇒ split; apply I
end.
Qed.
To see what branches are being tried, it can help to insert calls
to the identity tactic idtac. It optionally accepts an argument
to print out as debugging information.
Theorem match_ex2' : True ∧ True.
Proof.
match goal with
| [ ⊢ True ] ⇒ idtac "branch 1"; apply I
| [ ⊢ True ∧ True ] ⇒ idtac "branch 2"; split; apply I
end.
Qed.
Proof.
match goal with
| [ ⊢ True ] ⇒ idtac "branch 1"; apply I
| [ ⊢ True ∧ True ] ⇒ idtac "branch 2"; split; apply I
end.
Qed.
Only the second branch was tried. The first one did not match the
goal.
Ordinary match doesn't allow redundant branches.
Fail Definition redundant_match (n : nat) : nat :=
match n with
| x ⇒ x
| 0 ⇒ 1
end.
match n with
| x ⇒ x
| 0 ⇒ 1
end.
But match goal keeps trying until success.
Theorem match_ex2'' : True ∧ True.
Proof.
match goal with
| [ ⊢ _ ] ⇒ idtac "branch 1"; apply I
| [ ⊢ True ∧ True ] ⇒ idtac "branch 2"; split; apply I
end.
Qed.
Theorem match_ex2''' : True ∧ True.
Proof.
Fail match goal with
| [ ⊢ _ ] ⇒ idtac "branch 1"; apply I
| [ ⊢ _ ] ⇒ idtac "branch 2"; apply I
end.
Abort.
Proof.
match goal with
| [ ⊢ _ ] ⇒ idtac "branch 1"; apply I
| [ ⊢ True ∧ True ] ⇒ idtac "branch 2"; split; apply I
end.
Qed.
Theorem match_ex2''' : True ∧ True.
Proof.
Fail match goal with
| [ ⊢ _ ] ⇒ idtac "branch 1"; apply I
| [ ⊢ _ ] ⇒ idtac "branch 2"; apply I
end.
Abort.
Theorem match_ex3 : ∀ (P : Prop), P → P.
Proof.
intros P HP.
match goal with
| [ H : _ ⊢ _ ] ⇒ apply H
end.
Qed.
Proof.
intros P HP.
match goal with
| [ H : _ ⊢ _ ] ⇒ apply H
end.
Qed.
H is bound to HP, as shown by printout from idtac
H.
Theorem match_ex3' : ∀ (P : Prop), P → P.
Proof.
intros P HP.
match goal with
| [ H : _ ⊢ _ ] ⇒ idtac H; apply H
end.
Qed.
Proof.
intros P HP.
match goal with
| [ H : _ ⊢ _ ] ⇒ idtac H; apply H
end.
Qed.
Theorem match_ex4 : ∀ (P Q : Prop), P → Q → P.
Proof.
intros P Q HP HQ.
match goal with
| [ H : _ ⊢ _ ] ⇒ idtac H; apply H
end.
Qed.
Proof.
intros P Q HP HQ.
match goal with
| [ H : _ ⊢ _ ] ⇒ idtac H; apply H
end.
Qed.
Theorem match_ex5 : ∀ (P Q R : Prop), P → Q → R.
Proof.
intros P Q R HP HQ.
Fail match goal with
| [ H : _ ⊢ _ ] ⇒ idtac H; apply H
end.
Abort.
Proof.
intros P Q R HP HQ.
Fail match goal with
| [ H : _ ⊢ _ ] ⇒ idtac H; apply H
end.
Abort.
Theorem match_ex5 : ∀ (P Q : Prop), P → Q → P.
Proof.
intros P Q HP HQ.
match goal with
| [ H : ?X ⊢ ?X ] ⇒ idtac H; apply H
end.
Qed.
Proof.
intros P Q HP HQ.
match goal with
| [ H : ?X ⊢ ?X ] ⇒ idtac H; apply H
end.
Qed.
That applies only HP, because HQ doesn't match.
With match against terms, pattern variables can't be repeated:
Fail Definition dup_first_two_elts (lst : list nat) :=
match lst with
| x :: x :: _ ⇒ true
| _ ⇒ false
end.
match lst with
| x :: x :: _ ⇒ true
| _ ⇒ false
end.
The technical term for this is linearity: regular match
requires pattern variables to be linear, meaning that they are
used only once. Tactic match goal permits non-linear
metavariables, meaning that they can be used multiple times in a
pattern and must bind the same term each time.
Now that we've learned a bit about match goal, let's return to the proof pattern of some simple inductions:
Theorem app_nil_r' : ∀ (X : Type) (lst : list X),
lst ++ [] = lst.
Proof.
intros X lst. induction lst as [ | h t IHt].
- reflexivity.
- simpl. rewrite IHt. reflexivity.
Qed.
lst ++ [] = lst.
Proof.
intros X lst. induction lst as [ | h t IHt].
- reflexivity.
- simpl. rewrite IHt. reflexivity.
Qed.
With match goal, we can automate that proof pattern:
Ltac simple_induction t :=
induction t; simpl;
try match goal with
| [H : _ = _ ⊢ _] ⇒ rewrite H
end;
reflexivity.
Theorem app_nil_r'' : ∀ (X : Type) (lst : list X),
lst ++ [] = lst.
Proof.
intros X lst. simple_induction lst.
Qed.
induction t; simpl;
try match goal with
| [H : _ = _ ⊢ _] ⇒ rewrite H
end;
reflexivity.
Theorem app_nil_r'' : ∀ (X : Type) (lst : list X),
lst ++ [] = lst.
Proof.
intros X lst. simple_induction lst.
Qed.
Theorem add_assoc'' : ∀ n m p : nat,
n + (m + p) = (n + m) + p.
Proof.
intros n m p. induction n.
- reflexivity.
- simpl. rewrite IHn. reflexivity.
Qed.
Theorem add_assoc''' : ∀ n m p : nat,
n + (m + p) = (n + m) + p.
Proof.
intros n m p. simple_induction n.
Qed.
Theorem plus_n_Sm : ∀ n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction n.
- reflexivity.
- simpl. rewrite IHn. reflexivity.
Qed.
Theorem plus_n_Sm' : ∀ n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. simple_induction n.
Qed.
n + (m + p) = (n + m) + p.
Proof.
intros n m p. induction n.
- reflexivity.
- simpl. rewrite IHn. reflexivity.
Qed.
Theorem add_assoc''' : ∀ n m p : nat,
n + (m + p) = (n + m) + p.
Proof.
intros n m p. simple_induction n.
Qed.
Theorem plus_n_Sm : ∀ n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction n.
- reflexivity.
- simpl. rewrite IHn. reflexivity.
Qed.
Theorem plus_n_Sm' : ∀ n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. simple_induction n.
Qed.