检查返回值的策略中的evars

时间:2017-08-29 22:12:43

标签: coq coq-tactic

我试图编写一个返回值的策略,并且在这样做的过程中,它需要检查某些东西是否是一个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.

2 个答案:

答案 0 :(得分:2)

这是众所周知的Ltac限制:你不能写出有时会返回一个值的策略,有时会返回另一种策略。解决方案是用延续传递方式重写你的策略。不幸的是,我无法详细解释如何执行此操作,但Adam Chlipala的CDPT有chapter on Ltac来描述问题;只需寻找"继续"在文中。

答案 1 :(得分:2)

你可以使用一个整洁(或讨厌)的小技巧将策略执行插入到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现在和过去的执行模型。

战术评估分为两个阶段:策略表达评估和战术运行。在战术运行期间,执行排序,细化,重写等。在战术表达评估期间,如果在战术表达的头部位置找到,则评估以下构造:

  • 策略调用已解决/跟随/内联/展开
  • 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中,战术引擎被重写以处理依赖的子目标。这引起了;语义的细微变化,只有在使用多个目标之间共享的evars时才能观察到这种变化。在重写中,开发者将lazymatch的语义改为“match而不回溯”,并解除了对“立即匹配生成策略”的限制。因此,你可以做一些奇怪的事情:

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也急切地评估它的分支。