Hello,
I'm trying to implement a (very simple tactic) intros_exist
such that intros_exist n
(with n : nat
) is equivalent to:
intro x1 ; intro x2 ; ... ; intro xn ; exists x1 ; ... ; exists xn
where x1
, ... xn
are fresh ident generated by Coq.
Here is a first approximation of this tactic:
Ltac intros_exist_aux n i0 e0 :=
match n with
| O => idtac "match 0" ; i0 (* this line should be | O => i0 ; e0 *)
| S ?n => let x := fresh "x" in let i1 := (intro x ; idtac "let i1 :=" ; i0) in let e1 := (exists x ; idtac "let i2 :=" ; e0) in let i2 := intros_exist_aux n i1 e1 in i2
end.
Basically, I'm trying to store the intro
s in i0 and the exists
in e0. Right now, in the base case, I just drop e0
, because, as seen below, I have an error before I can reach that and begin the exists
sequence. With the above code, if I write:
Goal forall (n m k: nat), exists (x y z: nat), x = n /\ y = m /\ z = k .
Proof.
intros_exist_aux 1 ltac:(idtac "foo") ltac:(idtac "bar").
intros_exist_aux 1 ltac:(idtac "foo") ltac:(idtac "bar").
every thing goes fines: I obtain two new variables x, x0 : nat
in the goal forall k : nat, exists x1 y z : nat, x1 = x /\ y = x0 /\ z = k
as expected.
However, if I replace, the two intros_exist 1 ...
with (one) intros_exist_aux 2 ltac:(idtac "foo") ltac:(idtac "bar")
which should do the same job, I get the following error:
Error: No matching clauses for match
Thus, the tactic does not seem currently able to store more than one recursive call. What is going wrong with the match?
Again, use lazymatch
if you want the real error message.
But basically you are giving a continuation that you are building as you intro right.
Then I think we can do simpler just like this:
Ltac foo n e :=
lazymatch n with
| 0 => e
| S ?n =>
let h := fresh "x" in
intro h ;
let e' := e ; exists h in
foo n e'
end.
Ltac bar n :=
let e := idtac "ok" in
foo n e.
lazymatch
is indeed more precise and tells me that x is already used
.
However, I cannot quite adapt your syntax, because as you do it, you will have the exist
in the reverse order as the one I'm expecting.
Still, I'm a bit surprised by the error I get: shouldn't ltac be able to handle alpha-conversion of bound variables on its own, or I'm missing something?
My tactic does
intro x ; intro y ; intro z ; exist x ; exist y ; exist z
isn't that what you want?
It's indeed weird that a variable gets bound twice since you are using fresh
…
Mmh, yes, you are totally right! Still, I would like to undersand why there is a problem
Ah now I see what's wrong.
What you are doing is fresh ; fresh ; fresh ; intro ; intro ; intro ; exist ; exist ; exsit
.
But since you do the intro
after all the fresh
, x
is always fresh, so you get three times x
.
Huh, I guess that's because the ltac let in
is not a real let in
Well I'm not sure because this works:
let x := fresh "x" in
let y := fresh "x" in
intros x y.
so it might be some sort of weird evaluation thing.
Last updated: Apr 20 2024 at 00:02 UTC