【问题标题】:Why does this OCaml functor not recognize the structure type?为什么这个 OCaml 仿函数不能识别结构类型?
【发布时间】:2019-07-30 14:22:10
【问题描述】:

我已经编写了以下仿函数和实例,

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.

这让我很困惑,因为我本以为编译器会发生这样的事情:

  1. 我们用函子构造BstSet(MyString),所以参数MMyString
  2. 这意味着当我们调用M.t 时,这是string
  3. 这意味着eltstring
  4. 这意味着,在insert 的签名中,我们有一个函数string -&gt; string tree -&gt; string tree

所以这应该编译。或者更直接地说,我会认为StringSet.elt 将等于string

【问题讨论】:

    标签: types ocaml


    【解决方案1】:

    定义

    module BstSet(M: OrderedSet) : Set = struct ... end
    

    没有说明 Set.eltM.t 之间的相等性(实际上,它们不需要相同,例如,实现可以将额外信息嵌入到 elt 类型中)。要表达这种平等,您必须添加sharing constraint,例如,

    module BstSet(M: OrderedSet) : Set with type elt = M.t = struct ... end
    

    或者,您可以删除模块类型并让编译器查看实现,例如,像这样

    module BstSet(M: OrderedSet) = struct ... end
    

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

    【讨论】:

      猜你喜欢
      • 2018-08-25
      • 2018-03-01
      • 2020-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 1970-01-01
      相关资源
      最近更新 更多