了解专精战术

Understanding specialize tactic

试图理解@keep_learning 的 我一步一步地浏览了这段代码:

Inductive nostutter {X:Type} : list X -> Prop :=
| ns_nil : nostutter []
| ns_one : forall (x : X), nostutter [x]
| ns_cons: forall (x : X) (h : X) (t : list X), nostutter (h::t) -> x <> h -> nostutter (x::h::t).

Example test_nostutter_4: not (nostutter [3;1;1;4]).
Proof.
  intro.
  inversion_clear H.
  inversion_clear H0.
  unfold not in H2.
  (* We are here *)
  specialize (H2 eq_refl).
  apply H2.
Qed.

这是执行专门化之前的内容

H1 : 3 <> 1
H : nostutter [1; 4]
H2 : 1 = 1 -> False
============================
False

这里是 eq Prop 其构造函数 eq_refl 用于 specialize:

Inductive eq (A:Type) (x:A) : A -> Prop :=
    eq_refl : x = x :>A

where "x = y :> A" := (@eq A x y) : type_scope.

我无法解释,这个命令是如何工作的:

specialize (H2 eq_refl).

我看过关于specialize in的参考手册,但是里面的解释太笼统了。据我了解,H2 中的“1 = 1”表达式满足 eq_refl 构造函数,因此 eq 命题为真。然后它简化了表达式:

True -> False => False

然后我们得到

H1 : 3 <> 1
H : nostutter [1; 4]
H2 : False
============================
False

有人可以给我提供一个最小的例子来解释 specialize 在做什么,这样我就可以自由使用它了吗?

更新

尝试使用 apply 模仿 specialize 的工作原理,我做了以下操作:

Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
  apply H in a.

这给出:

A : Type
B : Type
H : A -> B
a : B
============================
B

specialize几乎相同,只是假设名称不同。

在 test_nostutter_4 定理中我尝试了这个并且成功了:

remember (@eq_refl nat 1) as Heq.
apply H2 in Heq as H3.

它给我们:

H1 : 3 <> 1
H : nostutter [1; 4]
H2 : 1 = 1 -> False
Heq : 1 = 1
H3 : False
HeqHeq : Heq = eq_refl
============================
False

这个比较复杂,我们不得不引入一个新的假设Heq。但是我们得到了我们需要的 - 最后是 H3。

specialize 内部是否使用 remember 之类的东西?或者是否可以通过应用解决它但不记得?

specialize,以最简单的形式,简单地用应用于其他术语的假设替换给定的假设。

在这个证明中,

Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
  specialize (H a).
  exact H.
Qed.

我们最初有假设H: A -> B。当我们调用 specialize (H a) 时,我们将 H 应用到 a(在函数应用中应用)。这给了我们 B 类型的东西。 specialize 然后为我们摆脱旧的 H 并用应用程序的结果替换它。它赋予新假设相同的名称:H.

在你的例子中,我们有 H2: 1 = 1 -> False,这是一个从类型 1 = 1 到类型 False 的函数。这意味着应用于 eq_reflH2 属于 False 类型,即 H2 eq_refl: False。当我们使用策略 specialize (H2 eq_refl). 时,旧的 H2 被清除并被类型为 False 的新术语 (H2 eq_refl) 取代。不过,它保留了旧名称 H2

specialize 当您确定您只打算使用一个假设时很有用,因为它会自动摆脱旧的假设。一个缺点是旧名称可能不符合新假设的含义。但是,在你的例子和我的例子中,H 是一个足够通用的名称,它可以以任何一种方式工作。


你的更新...

specialize 是直接在 ltac 插件中定义的核心策略。它在内部不使用任何其他策略,因为它它的内部结构。

如果你想保留一个假设,你可以使用 as 修饰符,它对 specializeapply 都有效。在证明中

Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.

如果你这样做 specialize (H a) as H0.,而不是清除 H,它会引入一个新的假设 H0: Bapply H in a as H0. 具有相同的效果。