Types 如何在OCaml中跨模块使用GADT而不引发警告?
我有两个文件:gadt1.ml和gadt2.ml,第二个文件依赖于第一个文件 gadt1.ml:Types 如何在OCaml中跨模块使用GADT而不引发警告?,types,pattern-matching,ocaml,compiler-warnings,gadt,Types,Pattern Matching,Ocaml,Compiler Warnings,Gadt,我有两个文件:gadt1.ml和gadt2.ml,第二个文件依赖于第一个文件 gadt1.ml: type never type _ t1 = A1 : never t1 | B1 : bool t1 type _ t2 = A2 : string t2 | B2 : bool t2 let get1 : bool t1 -> bool = function B1 -> true let get2 : bool t2 -> bool = function B2 -> t
type never
type _ t1 = A1 : never t1 | B1 : bool t1
type _ t2 = A2 : string t2 | B2 : bool t2
let get1 : bool t1 -> bool = function B1 -> true
let get2 : bool t2 -> bool = function B2 -> true
gadt2.ml:
let get1 : bool Gadt1.t1 -> bool = function Gadt.B1 -> true
let get2 : bool Gadt1.t2 -> bool = function Gadt.B2 -> true
当我使用OCAML4.02.3(ocamlbuild gadt2.native
)编译时,我得到一个警告8,说明函数gadt2.get1并非详尽无遗。我很困惑,Gadt2.get1
会发出警告,而Gadt1.get1
和Gadt2.get2
不会
我的假设是,空类型never
不能等于bool
,因此Gadt2。get1
不应发出警告。另一方面,如果我使用参数A1
调用Gadt2.get1
,我会得到一个类型错误(根据需要)。警告是预期行为还是错误?我错过了什么
顺便说一下,将
-principal
添加到编译标志中不会改变任何东西。Gadt2
只能看到Gadt1
的接口,而不能看到它的实现。界面如下所示:
type never
type _ t1 = A1 : never t1 | B1 : bool t1
type _ t2 = A2 : string t2 | B2 : bool t2
val get1 : bool t1 -> bool
val get2 : bool t2 -> bool
请注意,typenever
是抽象的——没有什么可以阻止一个提供RHS的实现。特别是,您可以在gadt1.ml中编写type never=bool
,此时将A1
传递给get1
,因此需要为这种可能性做好准备
相比之下,string
是一种非抽象类型:它有一个已知的表示形式,因此它不可能等于bool
,因此A2
永远不能传递给get2
您似乎试图用never
声明一个类型,该类型不是抽象的,而是空的,将其表示公开为根本没有构造函数。不幸的是,OCaml并没有很好地支持这一点;定义一个编译器可以在本地判断为空的类型的能力有点奇怪,在本文中并没有真正提到。在模块签名中无法表示“此类型为空”
更新:我相信这已经改变了,你现在可以写:
type never = |
指出
从不
实际上是一个空类型,而不是一个抽象类型。正如本所说,问题在于签名中的类型t
是抽象的而不是空的。另一种方法是定义无人居住的类型:
module One = struct
type never = { impossible : 'a . 'a }
type _ t1 = A1 : never t1 | B1 : bool t1
type _ t2 = A2 : string t2 | B2 : bool t2
let get1 : bool t1 -> bool = function B1 -> true
let get2 : bool t2 -> bool = function B2 -> true
end
module Two = struct
let get1 : bool One.t1 -> bool = function One.B1 -> true
let get2 : bool One.t2 -> bool = function One.B2 -> true
end
这并没有给出任何详尽的警告。我今天遇到了同样的问题,花了很多时间寻找解决方案。 正如Ben和gsg所说,这确实是因为
类型从不
是抽象的。
在我看来,最优雅的解决方案是将其定义为私有变量
type never = private Never
这解决了“穷尽性”警告,并清楚地表明您已排除了创建此类变量的可能性。我怀疑这是一个错误。您应该在caml列表邮件列表中提问。谁是OCaml GADT的负责人并不这么认为。