coq - 从 GADT 检索约束以确保在 Coq 中耗尽模式匹配
问题描述
让我们定义两个助手类型:
Inductive AB : Set := A | B.
Inductive XY : Set := X | Y.
然后是其他两种依赖于XY
和的类型AB
Inductive Wrapped : AB -> XY -> Set :=
| W : forall (ab : AB) (xy : XY), Wrapped ab xy
| WW : forall (ab : AB), Wrapped ab (match ab with A => X | B => Y end)
.
Inductive Wrapper : XY -> Set :=
WrapW : forall (xy : XY), Wrapped A xy -> Wrapper xy.
注意WW
构造函数——它只能是类型Wrapped A X
和Wrapped B Y
.
现在我想进行模式匹配Wrapper Y
:
Definition test (wr : Wrapper Y): nat :=
match wr with
| WrapW Y w =>
match w with
| W A Y => 27
end
end.
但我得到错误
Error: Non exhaustive pattern-matching: no clause found for pattern WW _
为什么会这样?Wrapper
force 包含Wrapped
为A
version,类型签名 forceY
和构造函数同时WW
禁止存在。我不明白为什么还要考虑这个案子,而我却不得不检查它,这似乎是不可能的。A
Y
如何解决这种情况?
解决方案
让我们简化一下:
Inductive MyTy : Set -> Type :=
MkMyTy : forall (A : Set), A -> MyTy A.
Definition extract (m : MyTy nat) : nat :=
match m with MkMyTy _ x => S x end.
这失败了:
The term "x" has type "S" while it is expected to have type "nat".
笏。
这是因为我说
Inductive MyTy : Set -> Type
这使得第一个参数成为MyTy
的索引MyTy
,而不是参数。带参数的归纳类型可能如下所示:
Inductive list (A : Type) : Type :=
| nil : list A
| cons : A -> list A -> list A.
参数在 的左侧命名:
,并且在每个构造函数的定义中都不是forall
-d。(它们仍然存在于定义之外的构造函数类型中:cons : forall (A : Type), A -> list A -> list A
。)如果我将Set
a 参数设为MyTy
,则extract
可以定义:
Inductive MyTy (A : Set) : Type :=
MkMyTy : A -> MyTy A.
Definition extract (m : MyTy nat) : nat :=
match m with MkMyTy _ x => S x end.
这样做的原因是,在内部,amatch
忽略了您从外部了解的关于被检查者索引的任何信息。(或者,更确切地说,Gallina 中的底层match
表达式忽略了索引。当您在源代码中编写 a时,Coq 会尝试将其转换为原始形式,同时结合索引中的match
信息,但通常会失败。)m : MyTy nat
第一个版本extract
根本没关系。相反,匹配给了我S : Set
(名称由 Coq 自动选择)x : S
,并且根据构造函数MkMyTy
,没有提及nat
. 同时,因为MyTy
在第二个版本中有一个参数,我实际上得到了x : nat
. 这_
这次真的是占位符;必须把它写成_
,因为没有什么可以匹配的,你可以Set Asymmetric Patterns
让它消失。
我们区分参数和索引的原因是因为参数有很多限制——最明显的是,如果I
是带参数的归纳类型,那么参数必须作为变量出现在每个构造函数的返回类型中:
Inductive F (A : Set) : Set := MkF : list A -> F (list A).
(* ^--------^ BAD: must appear as F A *)
在您的问题中,我们应该尽可能地制作参数。例如match wr with Wrap Y w => _ end
位是错误的,因为XY
参数Wrapper
是一个索引,所以这个事实wr : Wrapper Y
被忽略了;你也需要处理这个Wrap X w
案子。Coq 还没来得及告诉你这些。
Inductive Wrapped (ab : AB) : XY -> Set :=
| W : forall (xy : XY), Wrapped ab xy
| WW : Wrapped ab (match ab with A => X | B => Y end).
Inductive Wrapper (xy : XY) : Set := WrapW : Wrapped A xy -> Wrapper xy.
现在你的test
编译(几乎):
Definition test (wr : Wrapper Y): nat :=
match wr with
| WrapW _ w => (* mandatory _ *)
match w with
| W _ Y => 27 (* mandatory _ *)
end
end.
因为拥有这些参数可以为 Coq 提供足够的信息,以供其match
使用Wrapped
's 索引中的信息。如果您发出Print test.
,您会看到有一些跳跃性的Y
通过原语match
s 传递有关索引的信息,否则会忽略它。有关详细信息,请参阅参考手册。
推荐阅读
- javascript - 更改数据表中的警告消息
- javascript - 使用 jspdf & angularfire2 存储
- memcached - Memcached 在 winginx 面板中自动停止
- javascript - 检查是否存在与订单相关的任何收据项目
- php - 使用 php 将从表单收到的 html 安全地发送到电子邮件
- scala - 在 Scala SBT 项目上加载属性文件时找不到文件异常
- vba - 使用 VBA 发送电子邮件时如何指示文件的位置
- tensorflow - 张量流定义的精确小批量
- javascript - React JS - 为子组件传递函数
- php - PHP-DI 使用带有工厂的注解注入