我理解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
在上面的上下文中,如果我破坏M.find n m
,它会将H分为true和false,而case_eq (M.find n m)
将H保持原样并添加单独的命题M.find (elt:=nat) n m = Some v
,我可以重写它以获得相同的效果如破坏。
有人可以解释一下这两种策略之间的区别以及应该使用哪种策略?
答案 0 :(得分:13)
destruct
和case_eq
家庭中的第一个基本策略称为case
。这种策略只能修改结论。当您键入case A
并且A
的类型T
具有归纳类型时,系统会通过所有类型构造函数的实例替换目标结论中的A
T
,如果需要,为这些构造函数的参数添加通用量化。这会创建与T
类型中的构造函数一样多的目标。公式A
从目标中消失,如果假设中有A
的任何信息,则此信息与在结论中替换它的所有新构造函数之间的链接将丢失。尽管如此,case
是一种重要的原始策略。
在结论中忽略假设中信息与A
实例之间的链接是一个很大的问题,因此开发人员提出了两个解决方案:case_eq
和destruct
。< / p>
个人而言,在撰写Coq&#39; Art书时,我建议我们在case
之上编写一个简单的策略,在A
和各种构造函数实例之间保持链接。平等。这就是现在称为case_eq
的策略。它与case
做同样的事情,但在目标中增加了一个额外的含义,其中暗示的前提是形式A = ...
的相等性,其中...
是每个构造函数的实例
大约在同一时间,提出了destruct
战术。 destruct
不是将替换的影响限制在目标的结论中,而是用类型为A
的构造函数的实例替换假设中出现的T
的所有实例。从某种意义上说,这是更清晰,因为它避免依赖额外的平等概念,但它仍然是不完整的,因为表达式A
可能是复合表达式f B
,如果出现B
在假设中但不是f B
A
和B
之间的链接仍将丢失。
<强>插图强>
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
额外的平等在这里非常有用。
在this question中,我建议开发人员在case_eq (a == b)
类型为(a == b)
时使用bool
,因为此类型是归纳的,而且信息量不大(构造函数没有参数)。但是当(a == b)
具有类型{a = b}+{a <> b}
(string_dec
函数的情况)时,构造函数的参数是有趣属性的证明,并且构造函数的参数的额外通用量化是足以提供相关信息,在这种情况下,a = b
代表第一个目标,a <> b
代表第二个目标。