我编写了以下函子和实例,
module type Set = sig
type elt
type t
val empty : t
val insert : elt -> t -> t
val find : elt -> t -> bool
end
module type OrderedSet = sig
type t
val compare : t -> t -> int
end
module BstSet(M: OrderedSet) : Set = struct
type elt = M.t
type t = M.t tree
let empty = Leaf
let rec insert x tr = match tr with
| Leaf -> Node(Leaf, x, Leaf)
| Node (lt, y, rt) -> let c = M.compare x y in
if c < 0 then Node (insert x lt, y, rt)
else if c > 0 then Node (lt, y, insert x rt)
else Node (lt, y, rt)
let rec find x tr = match tr with
| Leaf -> false
| Node (lt, y, rt) -> let c = M.compare x y in
if c = 0 then true
else if c < 0 then find x lt
else find x rt
end
module MyString : OrderedSet = struct
type t = string
let compare s1 s2 = compare s1 s2
end
module StringSet = BstSet(MyString);;
StringSet.empty |> StringSet.insert "abc";;
Run Code Online (Sandbox Code Playgroud)
编译器引发错误
StringSet.empty |> StringSet.insert "abc";;
^^^^^
Error: This expression has type string but an expression was expected of type
StringSet.elt = BstSet(MyString).elt
Command exited with code 2.
Run Code Online (Sandbox Code Playgroud)
这使我感到困惑,因为我本以为在编译器中会发生这样的事情:
BstSet(MyString)使用函子进行构造,因此参数M为MyString。 M.t为时string。elt就是string。insert,我们有一个功能string -> string tree -> string tree。因此,应对此进行编译。或者更直接地讲,我本来以为StringSet.elt等于string。
定义
module BstSet(M: OrderedSet) : Set = struct ... end
Run Code Online (Sandbox Code Playgroud)
一无所知之间的平等说, Set.elt和M.t(事实上,他们并不需要是相同的,例如,实现可以嵌入额外信息进入ELT型)。为了表达这种平等,您必须添加共享约束,例如,
module BstSet(M: OrderedSet) : Set with type elt = M.t = struct ... end
Run Code Online (Sandbox Code Playgroud)
或者,您可以删除模块类型,让编译器查看实现,例如,像这样
module BstSet(M: OrderedSet) = struct ... end
Run Code Online (Sandbox Code Playgroud)
当您不打算从模块中导出函子并将其仅用于内部目的时,这很有用。