为什么此OCaml函子无法识别结构类型?

Add*_*dem 2 ocaml types

我编写了以下函子和实例,

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)

这使我感到困惑,因为我本以为在编译器中会发生这样的事情:

  1. 我们BstSet(MyString)使用函子进行构造,因此参数MMyString
  2. 这意味着当我们称其M.t为时string
  3. elt就是string
  4. 这意味着,在的签名中insert,我们有一个功能string -> string tree -> string tree

因此,应对此进行编译。或者更直接地讲,我本来以为StringSet.elt等于string

ivg*_*ivg 5

定义

module BstSet(M: OrderedSet) : Set = struct ... end
Run Code Online (Sandbox Code Playgroud)

一无所知之间的平等说, Set.eltM.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)

当您不打算从模块中导出函子并将其仅用于内部目的时,这很有用。