I find my self (sort of) duplicating code because I want to the same tactics in the goal and in a hypothesis when they match. For example:
match goal with
| H : PATTERN |- _ => simpl in H; rewrite X in H; ... ; other_tactic in H
| |- PATTERN => simpl ; rewrite ; ... ; other_tactic
end.
If the tactics in the match cases becomes long, I essentially duplicate it, with some in clauses added, and this seem very unsatisfactory, in particular if I have many match clauses, so that I duplicate a lot of code.
Sometimes it is not because that I am matching, but simply that I have defined a custom tactic, but depending on the context I would like to apply it either to the goal or to a named hypothesis. For example:
Ltac my_tac H := simpl in H; rewrite X in H; ... ; other_tactic in H.
Ltac my_tac_goal := simpl ; rewrite X ; ... ; other_tactic.
Then I am again "duplicating" code.
Are there any ways of avoiding this kind of duplication?
At some point I wondered of the goal had a name, say GOAL, like hypothesis, so that simpl in GOAL was equivalent to simpl, but I suspect this is not the case. In that case I could drop the definition of my_tac_goal and then just call my_tac GOAL instead.
Any suggestions on how to avoid this kind of duplication would be appreciated.
PS I had a hard time coming up with a good title, so if somebody thinks of one that fits well, do not hesitate to change it.
The "name" of the goal in an in clause is |- *, but somehow I can't find a reference in the manual for this. E.g. the following works:
Goal 2+2=4 -> 2+2=4 -> 2+2=4.
intros H1 H2.
simpl in H1 |- *.
This applies simpl in H1 and the goal, but not in H2.
Indeed, the DRY principle is often a useful pattern, including for Coq developments!
Regarding the particular use case you describe, it seems you could benefit from the SSReflect tactical in?
Proof-of-concept:
Require Import ssreflect.
Section SomeTest.
Variables (T : Type) (a b : T).
Hypothesis L : a = b.
Ltac my_tac := simpl; rewrite L.
Lemma test (c : T) (H : let _t := tt in (* dummy let-in to exemplify [simpl] *)
(a, c) = (c, b)) :
let _t := tt in (b, c) = (c, a).
do [ my_tac ] in H.
my_tac.
exact: H.
Qed.
End SomeTest.
Obviously, the do [ … ] in H form won't be applicable for any tactic (e.g., an apply/view. tactic should be manually ported to some move/view. tactic), but nothing prevents you from extending the my_tac tactic (e.g., with some if-then-else…), so that relevant parts are adapted manually (or removed) to address both kinds of contexts.
Related
I'm reading the book Software Foundations and got stuck at the very beginning.
The author defined a boolean type and common operations:
Inductive bool: Type :=
| true
| false.
Definition orb (b1: bool) (b2: bool) : bool :=
match b1 with
| true => true
| false => b2
end.
So let's say we want to prove the correctness of the or function.
The author wrote a test followed by a proof:
Example test_orb1: (orb true false) = true.
Proof. simpl. reflexivity. Qed.
Could someone explain to me what simpl. reflexivity mean? Is there any other way we can prove this simple test?
simpl is a tactic evaluating the goal. In your case, after executing it, the goal will be left to true = true.
reflexivity is a tactic discharging goals of the shape x = x (in its simplest incarnation). What it does under the hood is to provide the proof term eq_refl : x = x as a solution to the current proof obligation.
Now, there are many ways to achieve this thing that ultimately will produce the same (rather trivial) proof eq_refl (try doing Print test_orb1.). First, the simpl operation is not needed because Coq will do some computations when applying a term (in particular when calling reflexivity). Second, you could obtain the same effect as reflexivity by calling constructor, apply eq_refl or refine eq_refl. These are tactics with different goals but that happen to coincide here.
It seems that at some point there was a file SfLib.v that was used for the Software Foundations course. However, the case command proposed in this file is not getting through in my case:
Require Omega. (* needed for using the [omega] tactic *)
Require Export Bool.
Require Export List.
Require Export Arith.
Require Export Arith.EqNat. (* Contains [beq_nat], among other things *)
(** * From Basics.v *)
Require String. Open Scope string_scope.
Ltac move_to_top x :=
match reverse goal with
| H : _ |- _ => try move x after H
end.
Tactic Notation "assert_eq" ident(x) constr(v) :=
let H := fresh in
assert (x = v) as H by reflexivity;
clear H.
Tactic Notation "Case_aux" ident(x) constr(name) :=
first [
set (x := name); move_to_top x
| assert_eq x name; move_to_top x
| fail 1 "because we are working on a different case" ].
Tactic Notation "Case" constr(name) := Case_aux Case name.
Tactic Notation "SCase" constr(name) := Case_aux SCase name.
Tactic Notation "SSCase" constr(name) := Case_aux SSCase name.
Tactic Notation "SSSCase" constr(name) := Case_aux SSSCase name.
Tactic Notation "SSSSCase" constr(name) := Case_aux SSSSCase name.
Tactic Notation "SSSSSCase" constr(name) := Case_aux SSSSSCase name.
Tactic Notation "SSSSSSCase" constr(name) := Case_aux SSSSSSCase name.
Tactic Notation "SSSSSSSCase" constr(name) := Case_aux SSSSSSSCase name.
Fixpoint ble_nat (n m : nat) : bool :=
match n with
| O => true
| S n' =>
match m with
| O => false
| S m' => ble_nat n' m'
end
end.
Theorem andb_true_elim1 : forall b c,
andb b c = true -> b = true.
Proof.
intros b c H.
destruct b.
Case "b = true".
reflexivity.
Case "b = false".
rewrite <- H. reflexivity. Qed.
In the first case, I'm getting No interpretation for string "b = true".
This was previously addressed in coq error when trying to use Case. Example from Software Foundations book. However, the solution there does no longer work. Should I get rid of all the case statements?
Maybe something changed since then, but now we need to Import notations.
(* 8.9, 8.10, and newer *)
From Coq Require String.
Export String.StringSyntax. (* [Export] means to [Import] the StringSyntax module, but also make it automatically available to whoever imports this file as well. *)
Open Scope string_scope.
(* 8.8 and older (still works with 8.9, 8.10, but pollutes the namespace) *)
From Coq Require Export String.
Open Scope string_scope.
However, as evidenced by the removal of the module, the benefit of this trick is quite minor. Most people just use bullets, with comments to indicate the cases if they even care to comment.
Above, Open Scope is used, which may be fine for self-contained projects like SF, but for big and open projects, to avoid surprises with notations, I would recommend only using Local Open Scope (which then needs to appear in every file), or keeping Open Scope inside inner modules (that still need to be imported explicitly, but can be reexported together with others).
Inductive Foo : nat -> Type :=
| a : Foo 1.
(* ... *)
Goal forall m, Foo m -> m = 1.
Proof.
auto.
Fail Qed.
Is there a straightforward approach to do this?
You can use Hint Extern together with a tactic script that executes the case analysis. For example, this one will use destruct if the argument is a variable, and use inversion_clear otherwise:
Inductive Foo : nat -> Type :=
| a : Foo 1.
Hint Extern 1 => match goal with
| [ H : Foo ?m |- _ ]
=> first [ is_var m; destruct H | inversion_clear H ]
end.
Goal forall m, Foo m -> m = 1.
Proof.
auto.
Qed.
Via Programming Language Foundations, chapter Theory and Practice of Automation in Coq Proofs:
Note that proof search tactics never perform any rewriting step (tactics rewrite, subst), nor any case analysis on an arbitrary data structure or property (tactics destruct and inversion), nor any proof by induction (tactic induction). So, proof search is really intended to automate the final steps from the various branches of a proof. It is not able to discover the overall structure of a proof.
So there is really no way to do this; this goal should be solved manually, and then added to the hint database (Hint blah.).
I'm reading Coq reference manual (8.5p1) about
Local application of tactics
Different tactics can be applied to the different goals using the
following form:
[ > expr1 | ::: | exprn ]
The expressions expri are evaluated to vi, for i = 0; ...; n and all
have to be tactics. The vi is applied to the i-th goal, for = 1; ...;
n. It fails if the number of focused goals is not exactly n.
So I did a little test with two goals trying to apply two trivial idtac tactics to each, as follows:
Goal forall P Q: Prop, P \/ Q -> Q \/ P.
intros. destruct H. [ > idtac | idtac ].
However, I got an error telling me that only one tactic is expected:
Error: Incorrect number of goals (expected 1 tactic).
I'm confused. Can some one explain what I did wrong, and what's the correct usage?
The key part here is
It fails if the number of focused goals is not exactly n.
You need 2 focused goals.
The number of focused goals can be checked like this:
Ltac print_numgoals := let n := numgoals in idtac "# of goals:" n.
Goal forall P Q: Prop, P \/ Q -> Q \/ P.
intros. destruct H.
print_numgoals. (* prints 1 *)
There is a number of ways of getting several focused goals:
(1) Using sequencing: destruct H; [> idtac | idtac].
(2) Or slightly shorter: destruct H; [> idtac ..].
(3) Using the all selector (see the manual, §8.1):
destruct H. all: [ > id_tac | id_tac ].
In this last case, destruct H. all: print_numgoals. prints 2.
In conclusion, the following should be mentioned -- it seems that local application of tactics in that exact form ([ > ...]) is not very useful, because it is never used in the standard library (and several other libraries) and there are no mentions of it in the manual, except for the section devoted to this feature. Its version of the form expr; [ expr_1 | ... | expr_n] seems to be the most useful.
Let us assume that we want to prove the following (totally contrived) lemma.
Lemma lem : (forall n0 : nat, 0 <= n0 -> 0 <= S n0) -> forall n, le 0 n.
We want to apply nat_ind to prove it. Here is a possible proof:
Proof.
intros H n. apply nat_ind. constructor. exact H.
Qed.
But why not directly using H in the apply tactic, using something like apply (nat_ind _ _ H) or eapply (nat_ind _ _ H) ? But the first one fails, and the second one hides the remaining goal in an existential variable.
Is it possible in apply or its derivatives to skip hypotheses in order to specify the other arguments while keeping them as classic goals in the remainder of the proof ?
If you do
intros. refine (nat_ind _ _ H _).
then you only have
0 <= 0
left. Is that useful in your case?
Another approach (more universal than in my other answer) would be using the apply ... with ... construct, like this:
intros H n.
apply nat_ind with (2 := H).
Here, 2 is referring to the inductive step parameter of nat_ind (see the Coq v8.5 reference manual, 8.1.3):
In a bindings list of the form (ref_1 := term_1) ... (ref_n := term_n), ref is either an ident or a num. ... If ref_i is some number n, this number denotes the n-th non dependent premise of the term, as determined by the type of term.
This partial proof
intros H n.
apply nat_ind, H.
will give you 0 <= 0 as the only subgoal left.
This approach uses the apply tactic, but does not answer the question in its generality, since it will work only if you want to instantiate the last parameter (which is the case for the example in the question).
Here is quote from the Coq reference manual:
apply term_1 , ... , term_n
This is a shortcut for apply term_1 ; [ .. | ... ; [ .. | apply term_n ]... ], i.e. for the successive applications of term_(i+1) on the last subgoal generated by apply term_i, starting from the application of term_1.
Also, since it's just syntactic sugar, the solution may be considered cheating (and, I guess, abuse of the original intent of the Coq tactics developers) in the context of the question.