关于 Ocaml 中模块签名的困惑
Confusion about signature of a module in Ocaml
这两个有什么区别吗?
我不知道应该将其中哪些放入我的 .mli
文件
module Comparable : sig
type t
val compare : t -> t-> int
end
module type Comparable = sig
type t
val compare : t -> t-> int
end
在real world ocaml
书中,作者说接口、签名、模块类型这些词可以互换使用。
PS:我很乐意将问题标题更改为更合适的标题,有什么建议吗?
假设您的文件名为 m.mli
。如果相应的 m.ml
文件中有模块 Comparable
,则第一个定义是您使用的定义。第二个是你用来声明模块类型的东西(只是模块的类型,而不是模块)。在第一种情况下,有一个实际的 compare
可以称为 M.Comparable.compare
。在第二种情况下,没有比较函数,只有类型声明。
无法确定哪个适合您。他们都说得通。
.mli
文件允许约束一个 .ml
文件,请参见下面的示例:
/* foo.ml */
let foo1 x y = x + y
let foo = foo1
/* foo.mli */
val foo : int -> int -> int
/* main.ml */
open Foo
let r = foo 4 5
/* let r = foo1 4 5 ;; */
ocamlbuild main.native
仅在使用 foo
时编译,使用 foo1
.
时编译失败
现在,当你定义一个模块时,你可以在定义这个模块时隐藏一些声明:
module Comparable : sig
/* the exposed interface */
end = struct
/* the computation */
end
或者,为模块定义类型:
module type Comparable = sig
/* the exposed interface */
end
稍后您将能够在代码中使用该类型来约束某些模块。
以上面给出的例子(!!删除.mli文件!!)
/* foo.ml */
let foo1 x y = x + y
let foo = foo1
/* main.ml */
module type T1 = sig
val foo : int -> int -> int
end
module F1 : T1 = Foo
let r = Foo.foo1 4 5
let r = F1.foo1 4 5 /* will fail because hiden by type T1 */
您的第一个代码片段定义了一个具有特定签名的模块
,第二个直接定义签名而不是模块。
要了解差异,您的代码示例可能会被重写为
module type COMPARABLE = sig
type t
val compare : t -> t-> int
end
module Comparable: COMPARABLE
module type Comparable = sig
type t
val compare : t -> t-> int
end
定义模块类型。在接口(例如 .mli
文件)内部,承诺实现(.ml
)包含相同的模块类型定义。
module Comparable : sig
type t
val compare : t -> t-> int
end
在接口中承诺提供相同类型的模块。相当于
module Comparable : Comparable
(假设确实定义了模块类型)。它指出相应的 .ml
包含一个名为 Comparable
.
的 子模块
你应该把两者中的哪一个放在你身上 .mli
取决于你想做出什么样的承诺。各有各的用处。
如果需要模块类型定义作为仿函数的参数,那么它们通常出现在接口中。实际上你的模块类型 Comparable
等于 Map.OrderedType
,仿函数的参数类型 Map.Make
.
上述子模块的一个用例是提供可以用作仿函数参数的东西。例如 .mli
可能如下所示:
type stuff = ...
val fancy : ... (* some operations on stuff *)
module Comparable : Comparable with type t=stuff
在这种形式中,它将使类型 stuff
可用作地图的键类型。
就是说,如果您的示例是完整的真实示例,那么我怀疑您需要模块类型定义,而不是子模块:子模块不会很有用;您没有任何操作来构造 t
类型的任何内容。
这两个有什么区别吗?
我不知道应该将其中哪些放入我的 .mli
文件
module Comparable : sig
type t
val compare : t -> t-> int
end
module type Comparable = sig
type t
val compare : t -> t-> int
end
在real world ocaml
书中,作者说接口、签名、模块类型这些词可以互换使用。
PS:我很乐意将问题标题更改为更合适的标题,有什么建议吗?
假设您的文件名为 m.mli
。如果相应的 m.ml
文件中有模块 Comparable
,则第一个定义是您使用的定义。第二个是你用来声明模块类型的东西(只是模块的类型,而不是模块)。在第一种情况下,有一个实际的 compare
可以称为 M.Comparable.compare
。在第二种情况下,没有比较函数,只有类型声明。
无法确定哪个适合您。他们都说得通。
.mli
文件允许约束一个 .ml
文件,请参见下面的示例:
/* foo.ml */
let foo1 x y = x + y
let foo = foo1
/* foo.mli */
val foo : int -> int -> int
/* main.ml */
open Foo
let r = foo 4 5
/* let r = foo1 4 5 ;; */
ocamlbuild main.native
仅在使用 foo
时编译,使用 foo1
.
现在,当你定义一个模块时,你可以在定义这个模块时隐藏一些声明:
module Comparable : sig
/* the exposed interface */
end = struct
/* the computation */
end
或者,为模块定义类型:
module type Comparable = sig
/* the exposed interface */
end
稍后您将能够在代码中使用该类型来约束某些模块。 以上面给出的例子(!!删除.mli文件!!)
/* foo.ml */
let foo1 x y = x + y
let foo = foo1
/* main.ml */
module type T1 = sig
val foo : int -> int -> int
end
module F1 : T1 = Foo
let r = Foo.foo1 4 5
let r = F1.foo1 4 5 /* will fail because hiden by type T1 */
您的第一个代码片段定义了一个具有特定签名的模块 ,第二个直接定义签名而不是模块。 要了解差异,您的代码示例可能会被重写为
module type COMPARABLE = sig
type t
val compare : t -> t-> int
end
module Comparable: COMPARABLE
module type Comparable = sig
type t
val compare : t -> t-> int
end
定义模块类型。在接口(例如 .mli
文件)内部,承诺实现(.ml
)包含相同的模块类型定义。
module Comparable : sig
type t
val compare : t -> t-> int
end
在接口中承诺提供相同类型的模块。相当于
module Comparable : Comparable
(假设确实定义了模块类型)。它指出相应的 .ml
包含一个名为 Comparable
.
你应该把两者中的哪一个放在你身上 .mli
取决于你想做出什么样的承诺。各有各的用处。
如果需要模块类型定义作为仿函数的参数,那么它们通常出现在接口中。实际上你的模块类型 Comparable
等于 Map.OrderedType
,仿函数的参数类型 Map.Make
.
上述子模块的一个用例是提供可以用作仿函数参数的东西。例如 .mli
可能如下所示:
type stuff = ...
val fancy : ... (* some operations on stuff *)
module Comparable : Comparable with type t=stuff
在这种形式中,它将使类型 stuff
可用作地图的键类型。
就是说,如果您的示例是完整的真实示例,那么我怀疑您需要模块类型定义,而不是子模块:子模块不会很有用;您没有任何操作来构造 t
类型的任何内容。