(值)构造函数中的全量化类型变量不能按需显式键入

时间:2016-12-12 15:49:14

标签: coq

我有以下GADT。

Inductive GADT : Type -> Type :=
| A : forall A, GADT A
| B : GADT bool.

以下数据类型包含一个带有全限定类型变量的构造函数。

Inductive Wrap A :=
| wrap : GADT A -> Wrap A
| unwrap : forall X, GADT X -> (X -> Wrap A) -> Wrap A.

然后我想定义一个使用unwrap中的函数的递归函数。

Fail Fixpoint wrappedGADT {A} (xs: Wrap A) : option (GADT A) :=
  match xs with
  | wrap _ x => Some x
  | unwrap _ _ fx k => match fx with
                       | A _ => None
                       | B => wrappedGADT (k true)
                       end
end.

使用此定义,我收到以下错误消息。

The term "true" has type "bool" while it is expected to have type "T".

我假设当我检查fx并获取案例B时,参数fx的类型为GADT bool,因此,全量化的类型变量{{1 }}也是X。这个假设是错的吗?

接下来,我尝试按如下方式明确键入bool

unwrap

根据这个定义,我得到一个非常奇怪的错误信息。

Fail Fixpoint wrappedGADT {A} (xs: Wrap A) : option (GADT A) := match xs with | wrap _ x => Some x | @nwrap _ bool fx k => match fx with | A _ => None | B => wrappedGADT (k true) end end.

任何人都可以指出这个问题的根源吗?

2 个答案:

答案 0 :(得分:3)

不幸的是,Coq中的原始匹配语句对于您在此处应用的推理方式并不总是非常聪明。 “护航模式”(有关它的更多信息,请参阅CPDT)通常是解决此类问题的答案。这里的直接应用看起来像是:

Fail Fixpoint wrappedGADT {A} (xs: Wrap A) {struct xs} : option (GADT A) :=
  match xs with
  | wrap _ x => Some x
  | unwrap _ _ fx k => match fx in (GADT T)
                       return ((T -> Wrap A) -> option (GADT A)) with
                       | A _ => fun k0 => None
                       | B => fun k0 => wrappedGADT (k0 true)
                       end k
end.

但是,这会遇到另一个问题,即Coq在通过“车队”传递函数后无法验证终止条件。似乎要解决这个问题,首先要在k的值上定义递归调用的函数,然后对其进行控制:

Fixpoint wrappedGADT {A} (xs: Wrap A) {struct xs} : option (GADT A) :=
  match xs with
  | wrap _ x => Some x
  | unwrap _ _ fx k => let r := fun x => wrappedGADT (k x) in
                       match fx in (GADT T)
                       return ((T -> option (GADT A)) -> option (GADT A)) with
                       | A _ => fun _ => None
                       | B => fun r' => r' true
                       end r
end.

对于第二次代码尝试,您要创建一个局部变量bool来保存X构造函数中名为unwrap的类型,然后隐藏Datatypes.bool定义。一般来说,没有办法只匹配Coq内核语言中的一个特定类型(尽管类型类提供了一种模拟它的方法)。

答案 1 :(得分:3)

这是一个替代实现,它使用策略构造wrappedGADT的正文。它有一个优点,即它不需要用户手动return注释。整体结构与match表达式的原始代码非常相似。

在此处使用induction xs而不是destruct xs至关重要,因为Wrap类型是递归的。

Fixpoint wrappedGADT' {A} (xs: Wrap A) : option (GADT A).
  induction xs as [x | ? fx k r].
  - exact (Some x).
  - destruct fx as [T | ].
    + exact None.
    + exact (r true).
Defined.
Print wrappedGADT'.

这是两个实现在扩展上相等的证明。

Goal forall (A : Type) (xs : Wrap A),
    wrappedGADT xs = wrappedGADT' xs.
Proof with auto.
  intros A xs.
  induction xs...
  destruct g...
  simpl; rewrite H; destruct (w true)...
Qed.

如果我们查看为wrappedGADT'生成的术语(使用Print wrappedGADT'.),我们将能够使用为{{1}生成的Wrap_rect归纳原则构建另一个解决方案数据类型(我刚从Wrap中的k表达式中删除了未使用的变量match

wrappedGADT'

如果我们展开Definition wrappedGADT'' {A} (xs: Wrap A) : option (GADT A) := Wrap_rect _ _ (fun t => Some t) (fun _ fx k r => match fx in (GADT T) return ((T -> option (GADT A)) -> option (GADT A)) with | A _ => fun _ => None | B => fun r' => r' true end r) xs. ,此解决方案可以导致解决方案a-la Daniel's,实现为Wrap_rect本身。