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.t和Bar.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.t和Bar.t是一样的,而不会让它们“公开可见”?
在您的示例中,从类型检查器的角度来看,Foo.t和是完全不相关的类型。Bar.t确实,当你写
module Bar: Bar
Run Code Online (Sandbox Code Playgroud)
您将模块的类型Bar严格限制为Bar.t. 在模块 type 中Bar,Bar.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,您只能为其创建此类型的值,但永远不会破坏或消耗它们。