不同 ocaml 模块中的相同类型不匹配

Ant*_*ton 1 ocaml types module

我很抱歉这看起来像一个“琐事”问题,但这是我能想到的最简单的例子:

module type Foo = sig
  type 'a t

  val foo : 'a -> 'a t
end

module Foo : Foo = struct
  type 'a t = T of 'a

  let foo x = T x
end

(* Rewrap foo, add one function *)
module type Bar = sig
  include Foo

  val bar : int -> int t
end

module Bar : Bar = struct
  include Foo

  let bar n = foo (n + 1)
end

(* Specialization of Baz for integers *)
module type Baz = sig
  type t
  val bar : int -> t
end

module Baz : Baz = struct
  type t = int Foo.t
  let bar = Bar.bar
end
Run Code Online (Sandbox Code Playgroud)

在这个例子中Foo.tBar.t是完全相同的类型。所以因此int Foo.t与 相同int Bar.t

但是,我收到以下编译错误:

File "example.ml", lines 31-34, characters 19-3:
31 | ...................struct
32 |   type t = int Foo.t
33 |   let bar = Bar.bar
34 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = int Foo.t val bar : int -> int Bar.t end
       is not included in
         Baz
       Values do not match:
         val bar : int -> int Bar.t
       is not included in
         val bar : int -> t
       File "example.ml", line 28, characters 2-20: Expected declaration
       File "example.ml", line 33, characters 6-9: Actual declaration
Run Code Online (Sandbox Code Playgroud)

如果我替换type t = int Foo.t但是type t = int Bar.t,突然编译匹配。在我的原始代码中,我有很多东西都依赖于这两种类型。在我的例子中,就是这样,它永远不会编译:

File "example.ml", lines 31-34, characters 19-3:
31 | ...................struct
32 |   type t = int Foo.t
33 |   let bar = Bar.bar
34 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = int Foo.t val bar : int -> int Bar.t end
       is not included in
         Baz
       Values do not match:
         val bar : int -> int Bar.t
       is not included in
         val bar : int -> t
       File "example.ml", line 28, characters 2-20: Expected declaration
       File "example.ml", line 33, characters 6-9: Actual declaration
Run Code Online (Sandbox Code Playgroud)

我怎么能告诉编译器Foo.tBar.t是一样的,而不会让它们“公开可见”?

oct*_*ron 5

在您的示例中,从类型检查器的角度来看,Foo.t和是完全不相关的类型。Bar.t确实,当你写

module Bar: Bar
Run Code Online (Sandbox Code Playgroud)

您将模块的类型Bar严格限制为Bar.t. 在模块 type 中BarBar.t是一个抽象类型,与任何其他类型没有任何已知的关系。

如果要保留与Bar.t相同的信息Foo.t,则需要在模块类型约束中重新添加此信息:

module Bar : Bar with type 'a t = 'a Foo.t
Run Code Online (Sandbox Code Playgroud)

一般来说,当你开始在 OCaml 中编写模块类型时,最好从类型检查器推断的模块类型开始,并且只简单地删除信息。否则,人们经常使用完全不透明的模块类型来约束模块,这些模块类型会从模块中删除大量信息,从而使模块变得毫无用处。

例如,根据您的简化定义,

module type Foo = sig
  type 'a t
  val foo : 'a -> 'a t
end

module Foo : Foo = struct
  type 'a t = T of 'a
  let foo x = T x
end
Run Code Online (Sandbox Code Playgroud)

该模块Foo基本上是无用的,因为您有一个黑盒类型构造函数Foo.t,您只能为其创建此类型的值,但永远不会破坏或消耗它们。