Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Coq &引用;术语抽象化…;“定义不清”;解构时_Coq - Fatal编程技术网

Coq &引用;术语抽象化…;“定义不清”;解构时

Coq &引用;术语抽象化…;“定义不清”;解构时,coq,Coq,我在尝试销毁依赖类型的项时,经常在Coq中遇到错误。我知道有两个关于堆栈溢出的问题与这个问题有关,但这两个问题都不够一般,我无法在自己的证明中理解 下面是一个发生错误的简单示例 我们定义了一个类型族t: Inductive t: nat -> Set := | t_S: forall (n: nat), t (S n). 现在我们将试图证明这类家族的每个成员t(sn)都居住着一个术语,即t\sn Goal forall (n: nat) (p: t (S n)), p = t_S n.

我在尝试销毁依赖类型的项时,经常在Coq中遇到错误。我知道有两个关于堆栈溢出的问题与这个问题有关,但这两个问题都不够一般,我无法在自己的证明中理解

下面是一个发生错误的简单示例

我们定义了一个类型族
t

Inductive t: nat -> Set :=
| t_S: forall (n: nat), t (S n).
现在我们将试图证明这类家族的每个成员
t(sn)
都居住着一个术语,即
t\sn

Goal forall (n: nat) (p: t (S n)), p = t_S n.
我们从以下几点开始:

intros n p.
我的下一步是销毁
p

destruct p.
…但这会遇到以下错误:

Abstracting over the terms "n0" and "p" leads to a term fun (n1 : nat) (p0 : t n1) => p0 = t_S n
which is ill-typed.
Reason is: Illegal application: 
The term "@eq" of type "forall A : Type, A -> A -> Prop"
cannot be applied to the terms
 "t n1" : "Set"
 "p0" : "t n1"
 "t_S n" : "t (S n)"
The 3rd term has type "t (S n)" which should be coercible to "t n1".
在我看来,它似乎试图将
p
转换为
t_S n1
,但不知何故未能协调
n1
必须等于
n
这一事实,从而导致
=
的对侧具有不匹配的类型


为什么会发生这种情况?人们如何避免这种情况?

这一事实的一个简单证明是

Goal forall (n: nat) (p: t (S n)), p = t_S n.
Proof.
  intros n p.
  refine (
    match p with
    | t_S n => _
    end
  ).
  reflexivity.
Qed.
为了理解这是如何工作的,在这里查看Coq构造的证明项将有所帮助



Goal forall (n: nat) (p: t (S n)), p = t_S n.
Proof.
  intros n p.
  refine (
    match p with
    | t_S n => _
    end
  ).
  reflexivity.
  Show Proof.
因此证明项不是
p
上的简单匹配项。相反,Coq巧妙地概括了
p:t(sn)
中的
sn
,同时将目标类型更改为在
sn
情况下仍然匹配

具体来说,上面的证明术语使用类型

match (S n) as n' return (t n' -> Type) with
| 0 => fun p => IDProp (* Basically the same as `unit`; a singleton type *)
| S n' => fun p => p = t_S n'
end p
显然,这与
p=t_sn
相同,但它允许
sn
被推广。
n
的每个实例现在都是
sn
的形式,因此可以用一些
n'
来替换它。下面是如何用个人战术来写的

Goal forall (n: nat) (p: t (S n)), p = t_S n.
Proof.
  intro n.
  change (
    forall p: t (S n),
      match (S n) as n' return (t n' -> Type) with
      | 0 => fun p => Empty_set (* This can actually be any type. We may as well use the simplest possible type. *)
      | S n' => fun p => p = t_S n'
      end p
  ).
  generalize (S n); clear n.
  intros n p.
  (* p: t n, not t (S n), so we can destruct it *)
  destruct p.
  reflexivity.
Qed.

那么,为什么这一切都是必要的呢?归纳(作为一种特殊情况,案例匹配)要求归纳类型中的任何索引都是通用的。这可以通过查看
t
t\rect:forall(P:forall n:nat,tn->Type),(forall n:nat,P(sn)(t\sn))->forall(n:nat)(x:tn),pnx

当使用归纳法时,我们需要为所有自然数定义
p
。尽管归纳法的另一个假设,
forall n:nat,P(sn)(t_S n)
,只使用了
P(sn)
,但它仍然需要有一个值为零。对于您的目标,
P(sn)P:=(P=t_S n)
,但是没有为
0
定义
P
。改变目标的巧妙方法是将
P
扩展到
0
,以符合
sn
的定义

Goal forall (n: nat) (p: t (S n)), p = t_S n.