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 相同的效果。
谁能解释一下这两种策略的区别以及什么时候应该使用哪一种?
destruct
和 case_eq
家族中的第一个基本战术叫做 case
。此策略仅修改结论。当您键入 case A
且 A
具有归纳类型 T
时,系统会用类型 [=18= 的所有构造函数的实例替换目标结论中的 A
],如果需要,为这些构造函数的参数添加通用量化。这会创建与类型 T
中的构造函数一样多的目标。公式 A
从目标中消失,如果假设中有任何关于 A
的信息,则此信息与结论中替换它的所有新构造函数之间的 link 将丢失。尽管如此,case
是一种重要的原始战术。
假设中的信息与结论中A
的实例之间的信息丢失link在实践中是一个大问题,因此开发人员想出了两个解决方案:case_eq
和destruct
.
就我个人而言,在编写 Coq'Art 这本书时,我建议我们在 case
之上编写一个简单的策略,在 A
和各种构造函数实例之间保持一个 link以平等的形式。这就是现在称为 case_eq
的策略。它与 case
做同样的事情,但在目标中添加了一个额外的蕴涵,其中蕴涵的前提是 A = ...
形式的等式,其中 ...
是每个构造函数的实例.
大约在同一时间,destruct
的战术被提出来了。 destruct
不是在目标结论中限制替换的效果,而是将假设中出现的所有 A
实例替换为类型 T
的构造函数实例。从某种意义上说,这样更简洁,因为它避免了依赖额外的相等概念,但它仍然不完整,因为表达式 A
可能是复合表达式 f B
,如果 B
出现在假设中但不是 f B
A
和 B
之间的 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
。
我理解 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 相同的效果。
谁能解释一下这两种策略的区别以及什么时候应该使用哪一种?
destruct
和 case_eq
家族中的第一个基本战术叫做 case
。此策略仅修改结论。当您键入 case A
且 A
具有归纳类型 T
时,系统会用类型 [=18= 的所有构造函数的实例替换目标结论中的 A
],如果需要,为这些构造函数的参数添加通用量化。这会创建与类型 T
中的构造函数一样多的目标。公式 A
从目标中消失,如果假设中有任何关于 A
的信息,则此信息与结论中替换它的所有新构造函数之间的 link 将丢失。尽管如此,case
是一种重要的原始战术。
假设中的信息与结论中A
的实例之间的信息丢失link在实践中是一个大问题,因此开发人员想出了两个解决方案:case_eq
和destruct
.
就我个人而言,在编写 Coq'Art 这本书时,我建议我们在 case
之上编写一个简单的策略,在 A
和各种构造函数实例之间保持一个 link以平等的形式。这就是现在称为 case_eq
的策略。它与 case
做同样的事情,但在目标中添加了一个额外的蕴涵,其中蕴涵的前提是 A = ...
形式的等式,其中 ...
是每个构造函数的实例.
大约在同一时间,destruct
的战术被提出来了。 destruct
不是在目标结论中限制替换的效果,而是将假设中出现的所有 A
实例替换为类型 T
的构造函数实例。从某种意义上说,这样更简洁,因为它避免了依赖额外的相等概念,但它仍然不完整,因为表达式 A
可能是复合表达式 f B
,如果 B
出现在假设中但不是 f B
A
和 B
之间的 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
。