我无法理解 Coq (8.5p1, ch9.2) 分支和回溯行为中的多次成功
的概念。例如,来自文档:
Backtracking branching
We can branch with the following structure:
expr1 + expr2
Tactics can be seen as having several successes. When a tactic fails it asks for more successes of the prior tactics. expr1 + expr2 has all the successes of v1 followed by all the successes of v2.
我不明白的是,为什么我们首先需要多次成功?一次成功还不足以完成证明吗?
另外从文档来看,似乎有一些成本较低的分支规则在某种程度上是“有偏见的”,包括
first [ expr1 | ::: | exprn ]
和
expr1 || expr2
为什么我们需要成本更高的选项 +
而不是总是使用后者更有效的战术?
最佳答案
问题在于,您有时会尝试实现一个目标,但进一步的子目标可能会导致您认为可行的解决方案被拒绝。如果您积累了所有的成功,那么您可以回溯到您做出错误选择的地方,并探索搜索树的另一个分支。
这是一个愚蠢的例子。假设我想证明这个目标:
Goal exists m, m = 1.
现在,这是一个相当简单的目标,所以我可以手动完成,但我们不要这样做。让我们编写一个策略,当遇到 exists
时,尝试所有可能的自然数。如果我写:
Ltac existNatFrom n :=
exists n || existNatFrom (S n).
Ltac existNat := existNatFrom O.
然后,一旦我运行了 existNat
,系统就会提交第一个成功的选择。特别是这意味着尽管 existNatFrom
的递归定义,当调用 existNat
时,我总是会得到 O
并且只有 O
.
目标无法解决:
Goal exists m, m = 1.
Fail (existNat; reflexivity).
Abort.
另一方面,如果我使用 (+)
而不是 (||)
,我将遍历所有可能的自然数(以惰性方式,通过使用回溯)。所以写:
Ltac existNatFrom' n :=
exists n + existNatFrom' (S n).
Ltac existNat' := existNatFrom' O.
意味着我现在可以证明目标:
Goal exists m, m = 1.
existNat'; reflexivity.
Qed.
https://stackoverflow.com/questions/38256705/