Coq-类型的返回值等于函数的返回类型

时间:2019-03-29 17:44:58

标签: types coq typechecking

根据一些定理,我们知道类型super()等于类型A。在类型检查期间如何告诉Coq编译器?

我想实现一个非空树,以便每个节点知道其大小:

B

我想创建一个函数,该函数生成给定大小的对数深度的树。例如

Inductive Struct: positive -> Type := | Leaf : Struct 1%positive | Inner: forall {n m}, Struct n -> Struct m -> Struct (n + m).

7 -> 6 + 1 -> (3 + 3) + 1 -> ((2 + 1) + (2 + 1)) + 1 -> (((1 + 1) + 1) + ((1 + 1) + 1)) + 1

但是,我得到了错误:

  

“内部叶子(内部(nat2struct n0)(nat2struct n0))”一词的类型为“ Struct(1 +(n0 + n0))”,而预计其类型为“ Struct n0〜1”。

我该如何解决?我们知道Fixpoint nat2struct n : (Struct n) := match n with | xH => Leaf | xO n => Inner (nat2struct n) (nat2struct n) | xI n => Inner Leaf (Inner (nat2struct n) (nat2struct n)) end. ,但Coq却不知道。如果我以前说过这个定理,它什么都不会改变:

(1 + n + n) = xI n

Coq是否有一些提示可以知道这个定理?

PS1:该定理是否已在标准库中得到证明?我没找到。

PS2:我实际上想更自然地分裂:Theorem nBy2p1: forall n, Pos.add 1%positive (n + n) = xI n. Proof. Admitted. Hint Resolve nBy2p1. 。可能吗?我不知道如何编写它,以使Coq理解该函数收敛。

2 个答案:

答案 0 :(得分:3)

进行类型检查时,Coq使用较弱的相等形式(有时称为定义,判断或计算相等)。与命题相等(默认情况下绑定到“ =”)不同,定义相等是可以决定的。 Coq可以采用任意两个条件,并确定一个条件是否可以转换为另一个条件。如果类型检查中允许命题相等,则类型检查将不再是可确定的 1

要解决您的问题(这是一个很大的问题),您可以选择几种方法。

记录Struct

我将使用列表演示该原理。首先,我们有无大小列表的概念。

Inductive UnsizedList (A: Type) :=
| unil
| ucons (a: A) (u: UnsizedList A).

Arguments unil [A], A.
Arguments ucons [A] a u, A a u.

Fixpoint length {A: Type} (u: UnsizedList A) :=
match u with
| unil => 0
| ucons _ u' => S (length u')
end.

我们还可以定义一个大小列表,其中SizedList A n的每个元素的长度为n

Inductive SizedList (A: Type): nat -> Type :=
| snil: SizedList A 0
| scons {n: nat} (a: A) (u: SizedList A n): SizedList A (S n).

此定义遇到了与您完全相同的问题。例如,如果要显示串联是关联的,则不能简单地证明concat (concat u v) w = concat u (concat v w),因为等式的两侧具有不同的类型((i + j) + ki + (j + k))。如果我们可以简单地告诉Coq我们期望列表的大小,然后再证明,我们可以解决这个问题。这就是定义的作用,它将UnsizedList打包在一起,并证明该列表具有所需的长度。

Record SizedListPr (A: Type) (n: nat): Type := {
  list: UnsizedList A;
  list_len_eq: length list = n;
}.

现在我们可以拥有concat (concat u v) w = concat u (concat v w);我们只需要证明双方的长度为(i + j) + k

使用胁迫

如果您不小心的话,这种方法可能会变得很混乱,因此它通常不是首选方法。

让我定义一种强制类型,如果P x则将类型P y的元素映射到类型x = y的元素。 2

Definition coercion {A: Type} (P: A -> Type) {x y: A} (p: x = y): P x -> P y :=
match p with
| eq_refl => fun t => t
end.

在这里,我们对术语p: x = y使用归纳法。归纳原理从本质上说,如果我们可以证明xy在定义上相等,那么我们可以在命题相等时证明它。 3 P xP y是相同的,我们只能使用身份函数。

例如,现在,大小列表的串联关联性声明为concat (concat u v) w = coercion (SizedList A) (add_assoc) (concat u (concat v w))。因此,我们使用等号SizedList A (i + (j + k))SizedList A ((i + j) + k)类型的内容强制转换为add_assoc: i + (j + k) = (i + j) + k类型的内容(为便于阅读,我省略了一些参数)。


您要做出什么选择取决于您。关于此问题和相关问题的讨论,以及一些其他解决方案,可以在具有依赖类型的认证程序页面Equality中找到。


1 有关通常会发生这种情况的一类理论,请参见扩展类型理论Martin Hofmann's thesis概述了内涵理论和延伸理论之间的区别。

2 如果您熟悉同伦类型论,那就是transport

3 此声明有足够多的警告说明,命题平等和定义平等之间仍然存在差异。

答案 1 :(得分:0)

根据用户的回答,这是我最终得到的解决方案:

Inductive Struct: positive -> Type :=
| Leaf : Struct 1
| Inner : forall {lsize rsize size}
    (proof: Pos.add lsize rsize = size),
    (Struct lsize) -> (Struct rsize) -> Struct size.

Local Lemma nBy2: forall {n}, Pos.add n n = xO n.
Proof.
intros.
assert (Zpos (n + n) = Zpos (n~0)). { rewrite Pos2Z.inj_add. rewrite Z.add_diag. symmetry. apply Pos2Z.inj_xO. }
inversion H. auto.
Qed.

Local Lemma nBy2p1: forall {n}, Pos.add 1 (xO n) = xI n.
Proof.
intros. simpl.
assert (Zpos (1 + n~0) = Zpos (n~1)). { rewrite Pos2Z.inj_add. reflexivity. }
inversion H. auto.
Qed.

Fixpoint structCreate (size : positive) : (Struct size) :=
  match size with
  | xH => Leaf
  | xO n =>
    let child := structCreate n in
    Inner nBy2 child child
  | xI n => 
    let child := structCreate n in
    Inner nBy2p1 Leaf (Inner nBy2 child child)
  end.