Coq 中的 `destruct` 和 `case_eq` 策略有什么区别?

What is difference between `destruct` and `case_eq` tactics in Coq?

我理解 destruct 因为它将归纳定义分解为其构造函数。我最近看到 case_eq 但我不明白它有什么不同?

1 subgoals
n : nat
k : nat
m : M.t nat
H : match M.find (elt:=nat) n m with
    | Some _ => true
    | None => false
    end = true
______________________________________(1/1)
cc n (M.add k k m) = true

在上面的上下文中,如果我 destruct M.find n m 它会将 H 分解为 true 和 false 而 case_eq (M.find n m) 保持 H 不变并添加单独的命题 M.find (elt:=nat) n m = Some v,我可以将其重写为得到与 destruct 相同的效果。

谁能解释一下这两种策略的区别以及什么时候应该使用哪一种?

destructcase_eq 家族中的第一个基本战术叫做 case。此策略仅修改结论。当您键入 case AA 具有归纳类型 T 时,系统会用类型 [=18= 的所有构造函数的实例替换目标结论中的 A ],如果需要,为这些构造函数的参数添加通用量化。这会创建与类型 T 中的构造函数一样多的目标。公式 A 从目标中消失,如果假设中有任何关于 A 的信息,则此信息与结论中替换它的所有新构造函数之间的 link 将丢失。尽管如此,case 是一种重要的原始战术。

假设中的信息与结论中A的实例之间的信息丢失link在实践中是一个大问题,因此开发人员想出了两个解决方案:case_eqdestruct.

就我个人而言,在编写 Coq'Art 这本书时,我建议我们在 case 之上编写一个简单的策略,在 A 和各种构造函数实例之间保持一个 link以平等的形式。这就是现在称为 case_eq 的策略。它与 case 做同样的事情,但在目标中添加了一个额外的蕴涵,其中蕴涵的前提是 A = ... 形式的等式,其中 ... 是每个构造函数的实例.

大约在同一时间,destruct的战术被提出来了。 destruct 不是在目标结论中限制替换的效果,而是将假设中出现的所有 A 实例替换为类型 T 的构造函数实例。从某种意义上说,这样更简洁,因为它避免了依赖额外的相等概念,但它仍然不完整,因为表达式 A 可能是复合表达式 f B,如果 B 出现在假设中但不是 f B AB 之间的 link 仍然会丢失。

插图

Definition my_pred (n : nat) := match n with 0 => 0 | S p => p end.

Lemma example n :  n <= 1 -> my_pred n <= 0.
Proof.
case_eq (my_pred n).

给出两个目标

------------------
n <= 1 -> my_pred n = 0 -> 0 <= 0

------------------
forall p, my_pred n = S p -> n <= 1 -> S p <= 0

额外的相等在这里非常有用。

中,我建议开发人员在 (a == b) 具有类型 bool 时使用 case_eq (a == b),因为这种类型是归纳性的并且信息量不大(构造函数没有参数) .但是当 (a == b) 具有类型 {a = b}+{a <> b} 时(string_dec 函数就是这种情况),构造函数的参数是有趣属性的证明,并且构造函数参数的额外通用量化是足以提供相关信息,在本例中,第一个目标 a = b,第二个目标 a <> b