我无法理解Coq(8.5p1,ch9.2)分支和回溯行为中multiple successes
的概念。例如,来自文档:
回溯分支
我们可以使用以下结构进行分支:
expr1 + expr2
战术可以被视为取得了一些成功。当一个战术失败 它要求先前战术取得更多成功。 expr1 + expr2全部 v1的成功随后是v2的所有成功。
我不明白,为什么我们首先需要多次成功?难道没有一个成功足以完成证明吗?
同样来自文档,似乎有更低成本的分支规则以某种方式"有偏见",包括
first [ expr1 | ::: | exprn ]
和
expr1 || expr2
为什么我们需要更昂贵的选项+
而不是总是使用后者更有效的战术?
答案 0 :(得分:4)
问题在于,您有时会尝试实现目标,但进一步的子目标可能会导致您认为可能被拒绝的解决方案。如果您累积所有成功,那么您可以回溯到您做出错误选择的任何地方并探索搜索树的另一个分支。
这是一个愚蠢的例子。让我们说我想证明这个目标:
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.