以 returns 值的策略检查 evars
Check for evars in a tactic that returns a value
我正在尝试编写一个 return 是一个值的策略,并且在这样做的过程中它需要检查某些东西是否是 evar。
不幸的是,我不能使用 is_evar
,因为那样的话该策略不被视为 return 一个值(而是另一种策略)。下面是一个例子。
有什么建议吗?
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.
这是 Ltac 的一个众所周知的限制:您不能编写有时 returns 一个值,有时 returns 另一个策略的策略。解决方案是用 continuation-passing 风格 重写你的策略。不幸的是,我无法详细解释如何执行此操作,但是 Adam Chlipala 的 CDPT 有一个 chapter on Ltac 描述了这个问题;只需在文本中查找 "continuation"。
在 Coq >= 8.5 中,您可以使用一个简洁(或讨厌)的小技巧将策略执行插入到 constr 构造中:将其包装在 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.
因为编程语言的奥秘让我着迷,现在我将告诉您比您可能想知道的更多关于 Ltac 现在和过去的执行模型的信息。
战术评估有两个阶段:战术表达式评估和战术运行。在战术 运行 期间,执行排序、优化、重写等。在策略表达式评估期间,如果在策略表达式的头部位置找到以下构造,则对以下构造进行评估:
- 战术调用是resolved/followed/inlined/unfolded
let ... in ...
将其参数的表达式求值绑定到名称,并进行替换
constr:(...)
被评估和类型检查
lazymaytch ... with ... end
被求值(带回溯),returns 第一个匹配的分支成功表达式求值
match ... with ... end
被评估(带回溯) 并且分支被急切地执行 。请注意,在这张图片中,match
很奇怪,因为它强制提前执行策略。如果您曾在 Coq < 8.5 中看到 "immediate match producing tactics not allowed in local definitions",那是一条错误消息,明确禁止我在上面利用的行为。我猜这是因为 match
的这种奇怪行为是实现 Ltac 的原始开发人员想要隐藏的疣。因此,在 Coq 8.4 中,您唯一可以注意到它的地方是,如果您将 match
放在 lazymatch
中并尝试失败级别,并注意到 lazymatch
将在策略执行失败时回溯内部 match
当你通常认为它会失败时。
在 Coq 8.5 中,重写了策略引擎以处理依赖子目标。这引起了 ;
语义的细微变化,只有在使用多个目标之间共享的 evar 时才能观察到。在重写中,开发人员将 lazymatch
的语义更改为“match
无回溯”,并取消了对 "immediate match producing tactics." 的限制因此你可以做一些奇怪的事情,例如:
let dummy := match goal with _ => rewrite H end in
constr:(true)
并且有产生副作用的构造策略。但是,您不能再这样做了:
let tac := lazymatch b with
| true => tac1
| false => tac2
end in
tac long args.
因为在 Coq >= 8.5 中,lazymatch
也急切地评估它的分支。
我正在尝试编写一个 return 是一个值的策略,并且在这样做的过程中它需要检查某些东西是否是 evar。
不幸的是,我不能使用 is_evar
,因为那样的话该策略不被视为 return 一个值(而是另一种策略)。下面是一个例子。
有什么建议吗?
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.
这是 Ltac 的一个众所周知的限制:您不能编写有时 returns 一个值,有时 returns 另一个策略的策略。解决方案是用 continuation-passing 风格 重写你的策略。不幸的是,我无法详细解释如何执行此操作,但是 Adam Chlipala 的 CDPT 有一个 chapter on Ltac 描述了这个问题;只需在文本中查找 "continuation"。
在 Coq >= 8.5 中,您可以使用一个简洁(或讨厌)的小技巧将策略执行插入到 constr 构造中:将其包装在 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.
因为编程语言的奥秘让我着迷,现在我将告诉您比您可能想知道的更多关于 Ltac 现在和过去的执行模型的信息。
战术评估有两个阶段:战术表达式评估和战术运行。在战术 运行 期间,执行排序、优化、重写等。在策略表达式评估期间,如果在策略表达式的头部位置找到以下构造,则对以下构造进行评估:
- 战术调用是resolved/followed/inlined/unfolded
let ... in ...
将其参数的表达式求值绑定到名称,并进行替换constr:(...)
被评估和类型检查lazymaytch ... with ... end
被求值(带回溯),returns 第一个匹配的分支成功表达式求值match ... with ... end
被评估(带回溯) 并且分支被急切地执行 。请注意,在这张图片中,match
很奇怪,因为它强制提前执行策略。如果您曾在 Coq < 8.5 中看到 "immediate match producing tactics not allowed in local definitions",那是一条错误消息,明确禁止我在上面利用的行为。我猜这是因为match
的这种奇怪行为是实现 Ltac 的原始开发人员想要隐藏的疣。因此,在 Coq 8.4 中,您唯一可以注意到它的地方是,如果您将match
放在lazymatch
中并尝试失败级别,并注意到lazymatch
将在策略执行失败时回溯内部match
当你通常认为它会失败时。
在 Coq 8.5 中,重写了策略引擎以处理依赖子目标。这引起了 ;
语义的细微变化,只有在使用多个目标之间共享的 evar 时才能观察到。在重写中,开发人员将 lazymatch
的语义更改为“match
无回溯”,并取消了对 "immediate match producing tactics." 的限制因此你可以做一些奇怪的事情,例如:
let dummy := match goal with _ => rewrite H end in
constr:(true)
并且有产生副作用的构造策略。但是,您不能再这样做了:
let tac := lazymatch b with
| true => tac1
| false => tac2
end in
tac long args.
因为在 Coq >= 8.5 中,lazymatch
也急切地评估它的分支。