了解专精战术
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_refl
的 H2
属于 False
类型,即 H2 eq_refl: False
。当我们使用策略 specialize (H2 eq_refl).
时,旧的 H2
被清除并被类型为 False
的新术语 (H2 eq_refl
) 取代。不过,它保留了旧名称 H2
。
specialize
当您确定您只打算使用一个假设时很有用,因为它会自动摆脱旧的假设。一个缺点是旧名称可能不符合新假设的含义。但是,在你的例子和我的例子中,H
是一个足够通用的名称,它可以以任何一种方式工作。
你的更新...
specialize
是直接在 ltac 插件中定义的核心策略。它在内部不使用任何其他策略,因为它是它的内部结构。
如果你想保留一个假设,你可以使用 as
修饰符,它对 specialize
和 apply
都有效。在证明中
Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
如果你这样做 specialize (H a) as H0.
,而不是清除 H
,它会引入一个新的假设 H0: B
。 apply H in a as H0.
具有相同的效果。
试图理解@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_refl
的 H2
属于 False
类型,即 H2 eq_refl: False
。当我们使用策略 specialize (H2 eq_refl).
时,旧的 H2
被清除并被类型为 False
的新术语 (H2 eq_refl
) 取代。不过,它保留了旧名称 H2
。
specialize
当您确定您只打算使用一个假设时很有用,因为它会自动摆脱旧的假设。一个缺点是旧名称可能不符合新假设的含义。但是,在你的例子和我的例子中,H
是一个足够通用的名称,它可以以任何一种方式工作。
你的更新...
specialize
是直接在 ltac 插件中定义的核心策略。它在内部不使用任何其他策略,因为它是它的内部结构。
如果你想保留一个假设,你可以使用 as
修饰符,它对 specialize
和 apply
都有效。在证明中
Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
如果你这样做 specialize (H a) as H0.
,而不是清除 H
,它会引入一个新的假设 H0: B
。 apply H in a as H0.
具有相同的效果。