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
.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 ... end
is evaluated (with back tracking), and returns the first matching branch which successfully expression-evaluatesmatch ... with ... end
is evaluated (with backtracking) and the branch is eagerly executed. Note that in this picture,match
is 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 ofmatch
is 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 stickmatch
inside oflazymatch
and play with failure levels, and notice thatlazymatch
will backtrack across failures of tactic execution in the innermatch
when 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 oflazymatch
to mean "match
without 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,
lazymatch
also eagerly evaluates it's branches.