Coq (值)构造函数中的所有量化类型变量不能按需要显式类型化
我有下面的GADTCoq (值)构造函数中的所有量化类型变量不能按需要显式类型化,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. 然后我想定义一个递归函数,它使用
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
并得到caseB
时,参数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
而不是直接定义一个固定点,可能有足够的注释说明什么情况适合什么函数)。