Interface 关于Ocaml中模块签名的混淆

Interface 关于Ocaml中模块签名的混淆,interface,module,ocaml,signature,Interface,Module,Ocaml,Signature,这两者有什么区别吗 我不知道应该把它们中的哪一个放在.mli文件中 在现实世界的ocaml书中,作者说界面、签名、模块类型可以互换使用 PS:我很乐意将问题标题改为更合适的,有什么建议吗?说你的文件名为m.mli。如果对应的m.ml文件中有一个可比较的模块,那么第一个定义就是您所使用的。第二个是您用来声明模块类型的内容—只是模块的类型,而不是模块。在第一种情况下,有一个实际比较可以称为M.compariable.compare。在第二种情况下,没有比较函数,只有一个类型声明 不可能知道哪个是适合

这两者有什么区别吗

我不知道应该把它们中的哪一个放在.mli文件中

在现实世界的ocaml书中,作者说界面、签名、模块类型可以互换使用

PS:我很乐意将问题标题改为更合适的,有什么建议吗?

说你的文件名为m.mli。如果对应的m.ml文件中有一个可比较的模块,那么第一个定义就是您所使用的。第二个是您用来声明模块类型的内容—只是模块的类型,而不是模块。在第一种情况下,有一个实际比较可以称为M.compariable.compare。在第二种情况下,没有比较函数,只有一个类型声明

不可能知道哪个是适合你的。它们都有道理。

说您的文件名为m.mli。如果对应的m.ml文件中有一个可比较的模块,那么第一个定义就是您所使用的。第二个是您用来声明模块类型的内容—只是模块的类型,而不是模块。在第一种情况下,有一个实际比较可以称为M.compariable.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 */
.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 */

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


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

定义模块类型。在接口(例如.mli文件)中,承诺.ml的实现包含相同的模块类型定义

module Comparable : sig 
    type t
    val compare : t -> t-> int
end
在接口中,承诺提供相同类型的模块。这相当于

module Comparable : Comparable
假设模块类型确实已定义。它声明相应的.ml包含一个名为Comparable的子模块

你应该在这两个方面中选择哪一个。mli取决于你想要做出什么样的承诺。两者都有各自的用途

如果需要模块类型定义作为函子的参数,则通常可以在接口中找到它们。实际上,您的模块类型Compariable等于Map.OrderedType,即functor Map.Make的参数类型

上述子模块的一个用例是提供一些可以用作函子参数的东西。例如,一个.mli可以如下所示:

type stuff = ...
val fancy : ... (* some operations on stuff *)

module Comparable : Comparable with type t=stuff
在这种形式下,它将使类型stuff可用作映射的键类型

也就是说,如果您的示例是完整的真实示例,那么我怀疑您想要的是模块类型定义,而不是子模块:子模块将不会非常有用;您没有构造任何类型t的操作

定义模块类型。在接口(例如.mli文件)中,承诺.ml的实现包含相同的模块类型定义

module Comparable : sig 
    type t
    val compare : t -> t-> int
end
在接口中,承诺提供相同类型的模块。这相当于

module Comparable : Comparable
假设模块类型确实已定义。它声明相应的.ml包含一个名为Comparable的子模块

你应该在这两个方面中选择哪一个。mli取决于你想要做出什么样的承诺。两者都有各自的用途

如果需要模块类型定义作为函子的参数,则通常可以在接口中找到它们。实际上,您的模块类型Compariable等于Map.OrderedType,即functor Map.Make的参数类型

上述子模块的一个用例是提供一些可以用作函子参数的东西。例如,一个.mli可以如下所示:

type stuff = ...
val fancy : ... (* some operations on stuff *)

module Comparable : Comparable with type t=stuff
在这种形式下,它将使类型stuff可用作映射的键类型

也就是说,如果您的示例是完整的真实示例,那么我怀疑您想要的是模块类型定义,而不是子模块:子模块将不会非常有用;你有
没有构造任何类型t的操作

有没有一种方法可以保证您提供子模块类型并自动从子模块中的实现派生出该模块接口?@cmcdragokai:我不完全确定您的要求。如果你能从中提出一个实际的问题,也许会更好。简而言之,注释中的内容是:承诺提供模块类型B可以这样做:模块类型a=sig模块类型B结束。派生模块类型是这样完成的:模块类型a_类型=a_实现的模块类型。有没有办法保证您提供子模块类型并从子模块中的实现自动派生该模块接口?@CMCDRANGKAI:我不完全确定您在问什么。如果你能从中提出一个实际的问题,也许会更好。简而言之,注释中的内容是:承诺提供模块类型B可以这样做:模块类型a=sig模块类型B结束。导出模块类型的过程如下:模块类型a_类型=a_实现的模块类型。