Coq 带产品类型参数的谓词归纳法
如果我有这样一个谓词:Coq 带产品类型参数的谓词归纳法,coq,induction,coq-tactic,Coq,Induction,Coq Tactic,如果我有这样一个谓词: Inductive foo : nat -> nat -> Prop := | Foo : forall n, foo n n. Inductive bar' : nat -> nat -> nat -> nat -> Prop := | Bar' : forall n m, bar' n m n m. 然后我可以用归纳法证明一些伪引理: Lemma foo_refl : forall n n', foo n n' -&
Inductive foo : nat -> nat -> Prop :=
| Foo : forall n, foo n n.
Inductive bar' : nat -> nat -> nat -> nat -> Prop :=
| Bar' : forall n m, bar' n m n m.
然后我可以用归纳法证明一些伪引理:
Lemma foo_refl : forall n n',
foo n n' -> n = n'.
Proof.
intros.
induction H.
reflexivity.
Qed.
但是,对于具有产品类型参数的谓词:
Inductive bar : (nat * nat) -> (nat * nat) -> Prop :=
| Bar : forall n m, bar (n, m) (n, m).
几乎相同引理的类似证明被卡住了,因为所有关于变量的假设都消失了:
Lemma bar_refl : forall n n' m m',
bar (n, m) (n', m') -> n = n'.
Proof.
intros.
induction H.
(* :( *)
为什么会这样?如果我用反转来代替归纳,那么它的行为和预期的一样
引理仍然可以用归纳法证明,但需要一些变通方法:
Lemma bar_refl : forall n n' m m',
bar (n, m) (n', m') -> n = n'.
Proof.
intros.
remember (n, m) as nm.
remember (n', m') as n'm'.
induction H.
inversion Heqnm. inversion Heqn'm'. repeat subst.
reflexivity.
Qed.
不幸的是,这种方式的证明变得完全杂乱无章,对于更复杂的谓词是不可能遵循的
一个显而易见的解决方案是这样声明bar:
Inductive foo : nat -> nat -> Prop :=
| Foo : forall n, foo n n.
Inductive bar' : nat -> nat -> nat -> nat -> Prop :=
| Bar' : forall n m, bar' n m n m.
这解决了所有问题。然而,出于我的目的,我发现前面的元组方法稍微优雅一些。有没有办法让谓词保持原样,并且仍然能够进行易于管理的归纳证明?问题从何而来?问题在于归纳法只能处理变量,而不能处理构造的术语。这就是为什么你应该首先证明
Lemma bar_refl : forall p q, bar p q -> fst p = fst q.
现在归纳法1证明了这一点。来证明你的引理
如果你不想中间引理有一个名字,你的解决方案就是正确的:你需要帮助Coq记住概括你的目标,然后你就能证明它
我不记得这个限制是从哪里来的,但我记得一些关于使统一问题不可判定的事情。通常在这种情况下,人们可以对其中一个子项进行归纳 在你的例子中,你的引理可以用n上的归纳法证明 另一种方式
Lemma bar_refl n n' m m' : bar (n, m) (n', m') -> n = n'.
Proof.
change (n = n') with (fst (n,m) = fst (n',m')).
generalize (n,m) (n',m').
intros ? ? [ ]; reflexivity.
Qed.
。。。所有关于变量的假设都消失了。。。为什么会这样?如果我用反转来代替归纳,那么它的行为和预期的一样
这篇博文完美地描述了发生这种情况的原因:
詹姆斯·威尔科克斯。让我引用与本案最相关的部分:
当Coq执行案例分析时,它首先对所有索引进行抽象。在谓词上使用destruct时,您可能会将此清单视为信息丢失。请尝试Destruction甚至3例如:它只是删除了假设!,或者,当用具体的索引对谓词进行归纳时,尝试通过对假设而不是nat的归纳来证明所有n,甚至2*n+1->False-你会被卡住的!。Coq基本上忘记了指数的具体值。当试图引入这样一个假设时,一个解决方案是用一个新变量替换每个具体指标,并加上一个强制变量等于正确具体值的约束。析构函数做了类似的事情:当给定一个具有具体索引值的归纳类型的项时,它首先用新变量替换具体值。它不会添加相等约束,但会添加反转约束。这里的错误是关于提取索引。您不能仅仅用任意变量替换具体值,而希望事情仍然是类型检查。这只是一种启发
举一个具体的例子,当使用析构函数H时,基本上是这样进行模式匹配的:
Lemma bar_refl : forall n n' m m',
bar (n, m) (n', m') -> n = n'.
Proof.
intros n n' m m' H.
refine (match H with
| Bar a b => _
end).
具有以下证明状态:
n, n', m, m' : nat
H : bar (n, m) (n', m')
a, b : nat
============================
n = n'
为了获得几乎准确的证明状态,我们应该使用clear H命令从上下文中删除H。。。;清除H。。这种相当原始的模式匹配不允许我们证明我们的目标。
Coq抽象出n,m和n',m'用一些对p和p'替换它们,使得p=a,b和p'=a,b。不幸的是,我们的目标有n=n'的形式,其中既没有n,m也没有n',m',这就是为什么Coq没有用a=a来改变目标
但有一种方法可以告诉Coq这样做。我不知道如何使用战术做到这一点,所以我将展示一个证明项。它看起来有点类似于@Vinz的解决方案,但请注意,我没有改变引理的陈述:
Undo. (* to undo the previous pattern-matching *)
refine (match H in (bar p p') return fst p = fst p' with
| Bar a b => _
end).
这一次,我们为Coq添加了更多注释,以了解H类型的组件和目标之间的连接-我们明确地命名了p和p'对,因为我们告诉Coq将我们的目标视为fst p=fst p'它将用a,b替换目标中的p和p'。我们的证明状态现在如下所示:
n, n', m, m' : nat
H : bar (n, m) (n', m')
a, b : nat
============================
fst (a, b) = fst (a, b)
简单的自反性可以完成证明
我想现在应该很清楚为什么在下面的引理中析构函数可以很好地工作。不要看下面的答案,首先尝试弄清楚它:
Lemma bar_refl_all : forall n n' m m',
bar (n, m) (n', m') -> (n, m) = (n', m').
Proof.
intros. destruct H. reflexivity.
Qed.
回答:因为目标包含假设类型中存在的相同对,所以Coq将它们全部替换为适当的变量,这将防止信息丢失。啊,我明白了。看来坚持使用谓词的咖喱版本是我最好的选择……别忘了检查正确答案,以帮助未来的访问者