使用Signature / Functor模式,我在OCaml标准库中引用Map.S
/ Map.Make
的样式。当您希望在某种类型上参数化大量代码而不使其完全具有多态性时,此模式非常成功。基本上,您通过提供签名(通常称为S
)和构造函数(Make
)来引入参数化模块。
然而,当你仔细看看时,宣言中有很多冗余:
Summa summarum,我得到非抽象类型的3个定义网站(例如,当我想允许模式匹配时)。这完全是荒谬的,因此我认为有一些方法。所以我的问题是双重的:
答案 0 :(得分:1)
Foo_sigs
,包含签名并在其他地方使用它。答案 1 :(得分:1)
可以避免重复类型和模块类型定义,将它们移动到外部.ml
文件。我们来看下面的例子:
module M : sig
(* m.mli *)
module type S = sig
type t
val x : t
end
module type Result = sig
type t
val xs : t list
end
module Make(A : S) : Result with type t = A.t
end = struct
(* m.ml *)
module type S = sig
type t
val x : t
end
module type Result = sig
type t
val xs : t list
end
module Make(A : S) = struct
type t = A.t
let xs = [A.x;A.x]
end
end
我没有编写两个文件m.mli
和m.ml
,而是使用了一个带有显式签名的模块M
:这相当于拥有两个文件,你可以在OCaml toplevel上尝试它通过复制粘贴。
在M
中,事情在sig .. end
和struct .. end
中被欺骗。如果模块类型变大,这很麻烦。
您可以通过将这些欺骗移动到另一个.ml
文件来共享这些欺骗。例如,如下面的n_intf.ml
:
module N_intf = struct
(* n_intf.ml *)
module type S = sig
type t
val x : t
end
module type Result = sig
type t
val xs : t list
end
end
module N : sig
(* n.mli *)
open N_intf
module Make(A : S) : Result with type t = A.t
end = struct
(* n.ml *)
open N_intf
module Make(A : S) = struct
type t = A.t
let xs = [A.x;A.x]
end
end
您也可以使用*_intf.mli
代替*_intf.ml
,但我建议您使用*_intf.ml
,因为:
mli
个模块,因此您必须在安装时复制*_intf.cmi
。 .ml
中定义的内容。在这个例子中,由于没有类型定义,情况并非如此。答案 2 :(得分:0)
在这种特定情况下,您可以跳过.mli部分:
如果您在需要实际提供mli的组中工作,只需使用ocamlc -i
技巧自动生成它。
ocamlc -i m.ml >m.mli # automatically generate mli from ml
我知道它并没有完全回答你的问题,但是嘿,它解决了你的问题。
我知道总是使用mli被认为是最佳做法,但这不是强制性的,这可能是出于某些非常好的理由。
至于你的第二个问题,我不确定我是否理解得很好,但我认为这可以解决它:
module type ToCopy = sig type t val f : t -> unit end
module type Copy1 = sig include ToCopy with type t = int end
module type Copy2 = ToCopy with type t = int;;
答案 3 :(得分:0)
添加到camlspoter的答案,由于问题提到模式匹配,您可能希望使用N_intf
中声明的构造函数“重新导出”签名和类型,以便可以通过N
访问它们。在这种情况下,您可以将open
替换为include
和module type of
,即:
module N_intf = struct
type t = One | Two
(* n_intf.ml *)
module type S = sig
type t
val x : t
end
module type Result = sig
type t
val xs : t list
end
end
module N : sig
(* n.mli *)
include module type of N_intf
module Make(A : S) : Result with type t = A.t
end = struct
(* n.ml *)
include N_intf
module Make(A : S) = struct
type t = A.t
let xs = [A.x;A.x]
end
end
然后你会得到以下签名:
module N_intf :
sig
type t = One | Two
module type S = sig type t val x : t end
module type Result = sig type t val xs : t list end
end
module N :
sig
type t = One | Two
module type S = sig type t val x : t end
module type Result = sig type t val xs : t list end
module Make : functor (A : S) -> sig type t = A.t val xs : t list end
end
现在构造函数One
和Two
可以由N
而不是N_intf
限定,因此您可以忽略程序其余部分中的N_intf
。