为什么无法在这个依赖类型的程序中推断出0 + n = n?

时间:2016-03-14 13:40:20

标签: list type-inference coq dependent-type

我开始使用Coq,我想定义一些依赖类型的程序。请考虑以下事项:

Inductive natlist : nat -> Type :=
  | natnil : natlist 0
  | natcons : forall k, nat -> natlist k -> natlist (S k).

Fixpoint natappend (n:nat) (l1: natlist n) (m:nat) (l2: natlist m) : natlist (n+m) :=
  match l1 with
    | natnil => l2
    | natcons _ x rest => natcons (n+m) x (natappend rest l2)
  end.

因此natlist k将是nat长度k的列表。将连接定义为natappend的问题是以下错误:

Error:
In environment
natappend : forall n : nat,
            natlist n ->
            forall m : nat,
            natlist m -> natlist (n + m)
n : nat
l1 : natlist n
m : nat
l2 : natlist m
The term "l2" has type "natlist m"
while it is expected to have type
 "natlist (?n@{n1:=0} + m)".

正如您所看到的,该条款存在问题:

| natnil => l2

因为它声称l2的类型为natlist m,而结果类型必须为natlist (n+m) = natlist (0+m)

我知道Coq无法在类型级别解析任意表达式以避免非终止计算,但我发现很奇怪,即使这个简单的情况也不会被处理。

我在linux上运行CoqIDE,版本是:

The Coq Proof Assistant, version 8.5 (February 2016)
  compiled on Feb 22 2016 18:19:5 with OCaml 4.02.2

我已经看过使用MacOSX版本的实时课程,代码类似于上面在IDE中编译但没有出现错误,所以我有点困惑。

是否有一些设置我必须设置为启用更多类型推断并允许上述类型的代码?或者:我如何编写不依赖于类型推断的依赖类型代码?

2 个答案:

答案 0 :(得分:6)

问题是您的第二个分支中存在类型错误。这是一个有效的版本:

Fixpoint natappend {n m:nat} (l1 : natlist n) (l2 : natlist m) : natlist (n + m) :=
  match l1 with
  | natnil => l2
  | natcons n' x rest => natcons (n' + m) x (natappend rest l2)
  end.

此版本与原始版本之间的关键区别在于传递给natcons的参数:此处为n' + m,而在n + m之前。

此示例很好地说明了Coq中错误消息的非本地性的一般问题,特别是在编写依赖类型的程序时。即使Coq抱怨第一个分支,问题实际上是在第二个分支。在@jbapple建议的match语句中添加注释在尝试诊断出错时很有用。

答案 1 :(得分:3)

您需要match ... as ... in ... return ...来执行更复杂的类型注释。请参阅Adam Chlipala's chapter "Library MoreDep" in his Book "Certified Programming with Dependent Types""Chapter 17: Extended pattern-matching" in the Coq manual。两者都有您正在处理的concat示例。

您也可以将依赖类型位延迟到结束:

Definition natlist n := { x : list nat & n = length x }.

然后证明非依赖类型concat保留长度总和。