Coq (值)构造函数中的所有量化类型变量不能按需要显式类型化

Coq (值)构造函数中的所有量化类型变量不能按需要显式类型化,coq,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. 然后我想定义一个递归函数,它使用

我有下面的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
并得到case
B
时,参数
fx
具有类型
GADT bool
,因此,所有量化类型变量
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.
根据这个定义,我得到了一个非常奇怪的错误消息

The term "true" has type "bool" while it is expected to have type "T".
术语“true”的类型为“Datatypes.bool”,而预期的类型为“bool”。


有人能指出这个问题的根源吗?

不幸的是,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
,以保存
unwrap
构造函数中名为
X
的类型,然后该类型将隐藏
数据类型.bool
定义。一般来说,在Coq内核语言中,没有办法只匹配一种特定类型(尽管TypeClass提供了某种程度上模拟这种类型的方法)。

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

这里使用
inclusion 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.
),我们将能够使用为
Wrap
数据类型生成的
Wrap\rect
归纳原则构造另一个解决方案(我刚刚从
wrappedGADT'
中的
match
表达式中删除了未使用的变量
k
):


如果我们展开
Wrap\u rect
,作为
Fixpoint
本身实现,那么这个解决方案可以导致解决方案a-la。

我确实偶然发现了“护航模式”并尝试了一个类似于第一个代码示例的版本。第二个版本是否也类似于一种常见模式,或者是说服终止检查器更像是一种黑客行为?这里是否有其他更好的实现?说服终止检查器更像是一种黑客行为。尽管我是通过思考<代码>Wrap_-rect-这是另一种可能的编写方法(使用
Wrap_-rect
而不是直接定义一个固定点,可能有足够的注释说明什么情况适合什么函数)。