可以不用倒置来证明这个引理:重点是对适当的目标进行归纳(消除)。
首先请注意,当您将elim 应用于le n 0 类型的假设时,Coq 将应用与le 相关的消除原则。这里那个消除原理叫做le_ind,可以查询它的类型:
forall (n : nat) (P : nat -> Prop),
P n ->
(forall m : nat, n <= m -> P m -> P (S m)) ->
forall n0 : nat, n <= n0 -> P n0
这可能有点吓人,但重要的一点是,为了从假设 n <= n0 中证明目标 P n0,您需要考虑两种情况,一种用于 le 的每个构造函数。
那么这对您的问题有何帮助?假设n <= 0,这意味着你的目标应该是P(n0) 和n0 := 0。
现在考虑要证明n = 0,P 的形状应该是什么?
您可以尝试采用最简单的解决方案 P(n0) := n = 0(如果您在代码中直接调用 elim H,这实际上就是 Coq 正在做的事情)但是您无法证明您的两种情况中的任何一种。
问题是,选择P(n0) := n = 0,您忘记了n0 的值,因此您不能使用它等于0。解决这个问题的方法就是记住n0就是0,也就是设置P(n0) := n0 = 0 -> n = 0。
我们如何在实践中做到这一点?这是一种解决方案:
Goal forall n, le n 0 -> n = 0.
Proof.
intros n H.
remember 0 as q eqn: Hq. (* change all the 0s to a new variable q and add the equation Hq : q = 0 *)
revert Hq. (* now the goal is of the shape q = 0 -> n = 0 and H : le n q *)
elim H.
- intros; reflexivity. (* proves n = n *)
- intros; discriminate. (* discriminates S m = 0 *)
Qed.
所有这些泛化0 的工作实际上是inversion 试图为你做的。
请注意,我提出的谓词P 并不是唯一可能的解决方案。另一个有趣的解决方案是基于match(关键字是小规模反转)和P(n0) := match n0 with 0 => n = 0 | S _ => True end。
此外,战术最终总是会产生赤裸裸的加利纳术语,因此您总是可以(至少在理论上)写一个与任何战术证明相同的术语。下面是一个使用 Coq 强大但冗长的模式匹配的示例:
Definition pf : forall n, le n 0 -> n = 0 :=
fun n H =>
match H
in le _ q
return match q return Prop with
| 0 => n = q
| S _ => True
end
with
| le_n _ => match n with 0 => eq_refl | S _ => I end
| le_S _ _ _ => I
end.
编辑:使用remember 策略简化策略脚本。最初的提议是手动重新实现remember:
set (q := 0). (* change all the 0s in the goal into q and add it as hypothesis *)
intro H.
generalize (eq_refl : q = 0). (* introduce q = 0 *)
revert H.
generalize q ; clear q. (* generalizes q *)
(* Now the goal is of the shape
forall q : nat, n <= q -> q = 0 -> n = q
and we can apply elim *)
intros q H ; elim H.