我正在尝试编写一个返回值的策略,在此过程中需要检查某些内容是否是 evar。
不幸的是,我无法使用is_evar
,因为这样该策略不被视为返回值(而是另一种策略)。下面是一个例子。
有什么建议么?
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.
Run Code Online (Sandbox Code Playgroud)
有一个巧妙(或令人讨厌)的小技巧,您可以使用它在 Coq >= 8.5 中将策略执行插入到 constr 构造中:将其包装在match goal
.
Ltac reify_wrt 值 ls := 将 ls 与 | nil => constr:(@nil nat) | ?a :: ?ls' => let i := 查找 a 中的值 让 idx := reify_wrt 值 ls' in 构造:(i::idx) | ?e :: ?ls' => let check := 匹配目标与 _ => is_evar e 结尾 让 i := constr:(100) 进入 让 idx := reify_wrt 值 ls' in 构造:(i::idx) 结尾。
因为编程语言奥秘让我着迷,所以我现在将告诉您有关 Ltac 当前和过去的执行模型的更多信息,这些内容可能超出您想了解的内容。
策略评估有两个阶段:策略表达评估和策略运行。在策略运行过程中,会执行排序、细化、重写等操作。在策略表达式评估期间,如果在策略表达的头部位置找到以下结构,则评估以下结构:
let ... in ...
将其参数的表达式求值绑定到名称,并进行替换constr:(...)
进行评估和类型检查lazymaytch ... with ... end
被求值(使用回溯),并返回成功表达式求值的第一个匹配分支match ... with ... end
被评估(通过回溯)并且分支被急切地执行。请注意,在这张图中,match
很奇怪,因为它迫使战术提前执行。如果您在 Coq < 8.5 中见过“本地定义中不允许的立即匹配生成策略”,那么这是一条错误消息,明确禁止我在上面利用的行为。我猜这是因为这种奇怪的行为match
是实现 Ltac 的原始开发人员想要隐藏的一个缺陷。因此,在 Coq 8.4 中,您唯一能注意到它的地方是,如果您坚持match
在内部lazymatch
并尝试失败级别,并且会注意到,当您通常期望它失败时,它将lazymatch
在内部策略执行失败时进行回溯。match
在 Coq 8.5 中,策略引擎被重写以处理相关子目标。这导致了语义上的微妙变化,;
只有在使用多个目标之间共享的 evar 时才能观察到这种变化。在重写中,开发人员将 的语义更改lazymatch
为“match
不回溯”,并取消了对“立即匹配产生策略”的限制。因此你可以做一些奇怪的事情,比如:
let dummy := match goal with _ => rewrite H end in
constr:(true)
Run Code Online (Sandbox Code Playgroud)
并具有产生副作用的构造策略。但是,您不能再执行以下操作:
let tac := lazymatch b with
| true => tac1
| false => tac2
end in
tac long args.
Run Code Online (Sandbox Code Playgroud)
因为在 Coq >= 8.5 中,lazymatch
也急切地评估它的分支。