如何在 Coq 中将“+ 1”(加一)重写为 "S"(succ)?

How can I rewrite "+ 1" (plus one) to "S" (succ) in Coq?

我有以下证明不完整的引理:

Lemma s_is_plus_one : forall n:nat, S n = n + 1.
Proof.
  intros.
  reflexivity.
Qed.

此证明失败

Unable to unify "n + 1" with "S n".

似乎 eq_S 可以证明这一点,但我无法应用它(它无法将 n + 1 识别为 S nError: Unable to find an instance for the variable y.).我也试过 ring,但找不到关系。当我使用 rewrite 时,它只是减少到相同的最终目标。

我怎样才能完成这个证明?

这与(+)的定义方式有关。您可以通过关闭符号来访问 (+) 的底层定义(在 View > Display notations 中的 CoqIDE 中),看到符号 (+) 对应于函数 Nat.add 然后调用 Print Nat.add 这给你:

Nat.add = 
fix add (n m : nat) {struct n} : nat :=
  match n with
  | O => m
  | S p => S (add p m)
  end

你可以看到 (+) 是通过匹配它的第一个参数来定义的,在 n + 1 中是变量 n。因为 n 不是以 OS 开头(它不是 "constructor-headed"),所以 match 不能减少。这意味着你不能仅仅通过说这两个东西计算出相同的范式(这就是 reflexivity 所声称的)来证明相等性。

相反,您需要向 coq 解释为什么对于任何 n 等式都成立。对于像 Nat.add 这样的 递归 函数,一个经典的做法是通过 induction 进行证明。它确实在这里完成了工作:

Lemma s_is_plus_one : forall n:nat, S n = n + 1.
Proof.
intros. induction n.
 - reflexivity.
 - simpl. rewrite <- IHn. reflexivity.
Qed.

你可以做的另一件事是注意 1 另一方面是以构造函数为首的,这意味着只有你有 1 + n 而不是 n + 1 才会触发匹配。好吧,我们很幸运,因为在标准库中有人已经证明 Nat.add 是可交换的,所以我们可以直接使用它:

Lemma s_is_plus_one : forall n:nat, S n = n + 1.
Proof.
intros.
rewrite (Nat.add_comm n 1).
reflexivity.
Qed.

最后一个替代方案:使用 SearchAbout (?n + 1),我们可以找到所有关于某个变量 ?n 的模式 ?n + 1 的定理(这里的问号很重要)。第一个结果是真正相关的引理:

Nat.add_1_r: forall n : nat, n + 1 = S n