关于Ocaml中模块签名的困惑

时间:2017-03-11 15:37:17

标签: interface module ocaml signature

这两者有什么区别吗?

我不知道应该在.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 :我很乐意将问题标题更改为更合适的标题,任何提案?

4 个答案:

答案 0 :(得分:3)

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类型的任何东西。

答案 1 :(得分:2)

您的第一个代码片段定义了具有特定签名的模块 ,第二个直接定义签名而不是模块。 要了解其中的差异,可以将代码示例重写为

module type COMPARABLE = sig 
   type t
   val compare : t -> t-> int
end

module Comparable: COMPARABLE

答案 2 :(得分:1)

假设您的文件名为m.mli。如果相应的m.ml文件中包含模块Comparable,则第一个定义是您使用的定义。第二个是用于声明模块类型(仅仅是模块的类型,而不是模块)。在第一种情况下,实际compare可以称为M.Comparable.compare。在第二种情况下,没有比较函数,只是类型声明。

不可能知道哪个对你来说是正确的。它们都有意义。

答案 3 :(得分:1)

.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 */