I'm trying to write a tactic that returns a value, and in the course of doing so it needs to check if something is an evar.
Unfortunately, I can't use is_evar because then the tactic isn't deemed to return a value (but rather another tactic). An example is below.
Any suggestions?
Ltac reify_wrt values ls :=
match ls with
| nil => constr:(@nil nat)
| ?a :: ?ls' => let i := lookup a values in
let idx := reify_wrt values ls' in
constr:(i :: idx)
| ?e :: ?ls' => is_evar e;
let i := constr:(100) in
let idx := reify_wrt values ls' in
constr:(i :: idx)
end.
There is a neat (or nasty) little trick that you can use to insert tactic execution into constr construction in Coq >= 8.5: wrap it in
match goal.Ltac reify_wrt values ls := match ls with | nil => constr:(@nil nat) | ?a :: ?ls' => let i := lookup a values in let idx := reify_wrt values ls' in constr:(i :: idx) | ?e :: ?ls' => let check := match goal with _ => is_evar e end in let i := constr:(100) in let idx := reify_wrt values ls' in constr:(i :: idx) end.Because programming language arcana fascinate me, I'll now tell you more than you probably ever wanted to know about the present and past execution models of Ltac.
There are two phases of tactic evaluation: there is tactic expression evaluation, and tactic running. During tactic running, sequencing, refine, rewrite, etc, are executed. During tactic expression evaluation, the following constructs are evaluated, if found in the head position of the tactic expressing:
let ... in ...binds the expression-evaluation of it's argument to the name, and does substitutionconstr:(...)is evaluated and type checkedlazymaytch ... with ... endis evaluated (with back tracking), and returns the first matching branch which successfully expression-evaluatesmatch ... with ... endis evaluated (with backtracking) and the branch is eagerly executed. Note that in this picture,matchis strange, because it forces the execution of a tactic to come early. If you've ever seen "immediate match producing tactics not allowed in local definitions" in Coq < 8.5, that's an error message explicitly forbidding the behavior I'm exploiting above. I'm guessing it's because this strange behavior ofmatchis a wart that the original devs implementing Ltac wanted to hide. So the only place you can notice it in Coq 8.4 is if you stickmatchinside oflazymatchand play with failure levels, and notice thatlazymatchwill backtrack across failures of tactic execution in the innermatchwhen you would normally expect it to fail.In Coq 8.5, the tactic engine was rewritten to handle dependent subgoals. This induced subtle changes in the semantics of
;which can only be observed when using evars that are shared between multiple goals. In the rewrite, the devs changed the semantics oflazymatchto mean "matchwithout backtracking", and lifted the restriction on "immediate match producing tactics." Hence you can do strange things like:and have constr-producing tactics with side effects. However, you can no longer do:
because in Coq >= 8.5,
lazymatchalso eagerly evaluates it's branches.