我已经编写了以下函子和实例
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";;
并且编译器引发错误
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.
这使我感到困惑,因为我本以为在编译器中会发生这样的事情:
BstSet(MyString)
,因此自变量M
为MyString
。 M.t
时,它就是string
。 elt
是string
。insert
的签名中,我们有一个函数string -> string tree -> string tree
。所以应该编译。或者更直接地说,我本来以为StringSet.elt
等于string
。
答案 0 :(得分:5)
定义
module BstSet(M: OrderedSet) : Set = struct ... end
对Set.elt
和M.t
之间的相等性一无所知(实际上,它们不需要相同,例如,实现可以将额外的信息嵌入elt类型)。为了表达这种平等,您必须添加sharing constraint,例如
module BstSet(M: OrderedSet) : Set with type elt = M.t = struct ... end
或者,您可以删除模块类型,然后让编译器查看实现,例如
module BstSet(M: OrderedSet) = struct ... end
当您不打算从模块中导出函子并将其仅用于内部目的时,这很有用。