Types 如何在OCaml中跨模块使用GADT而不引发警告?

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

我有两个文件: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 -> 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的负责人并不这么认为。