繁体   English   中英

在OCaml中实现Okasaki的自举堆,为什么不编译?

[英]Implementing Okasaki's bootstrapped heaps in OCaml, why doesn't it compile?

(一个最小的非编译示例可以在https://gist.github.com/4044467上找到,请参阅下面的更多背景。)

我正在尝试实现Okasaki的Pure Functional Data Structure第10章中介绍的Bootstrapped堆 以下是我的非编译代码的简化版本。

我们将使用以下签名实现堆:

module type ORDERED =
sig
  type t
  val compare : t -> t -> int
end

module type HEAP =
sig
  module Elem : ORDERED

  type heap

  val empty : heap
  val insert : Elem.t -> heap -> heap
  val find_min : heap -> Elem.t
  val delete_min : heap -> heap
end

我们说一个数据结构的实现依赖于相同类型数据结构的另一个实现而被引导 因此,我们有一个这样的堆(实际的实现并不重要):

module SomeHeap (Element : ORDERED) : (HEAP with module Elem = Element) =
struct
  module Elem = Element

  type heap

  let empty = failwith "skipped"
  let insert = failwith "skipped"
  let find_min = failwith "skipped"
  let delete_min = failwith "skipped"
end 

然后,我们将要实现的自举堆(可能依赖于任何堆实现)应该具有以下签名:

module BootstrappedHeap
  (MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
  (Element : ORDERED) : (HEAP with module Elem = Element)

因此我们可以像这样使用它:

module StringHeap = BootstrappedHeap(SomeHeap)(String)

冈崎说,BootstrappedHeap的实现是这样的:

module BootstrappedHeap
  (MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
  (Element : ORDERED) : (HEAP with module Elem = Element) =
struct
  module Elem = Element

  module rec BootstrappedElem :
  sig
    type t =
      | E
      | H of Elem.t * PrimH.heap
    val compare : t -> t -> int
  end =
  struct
    type t =
      | E
      | H of Elem.t * PrimH.heap
    let compare t1 t2 = match t1, t2 with
      | H (x, _), H (y, _) -> Elem.compare x y
      | _ -> failwith "unreachable"
  end
  and PrimH : (HEAP with module Elem = BootstrappedElem) =
    MakeH(BootstrappedElem)

  type heap

  let empty = failwith "not implemented"
  let insert = failwith "not implemented"
  let find_min = failwith "not implemented"
  let delete_min = failwith "not implemented"
end

但这还没有编译! 错误消息是:

File "ordered.ml", line 52, characters 15-55:
Error: In this `with' constraint, the new definition of Elem
       does not match its original definition in the constrained signature:
       Modules do not match:
         sig type t = BootstrappedElem.t end
       is not included in
         ORDERED
       The field `compare' is required but not provided

52行是

and PrimH : (HEAP with module Elem = BootstrappedElem) =

我认为BootstrappedElem确实实现了ORDERED因为它同时具有tcompare ,但是我看不到为什么编译器无法找到compare函数。

将BootstrappedElem的签名更改为

module rec BootstrappedElem : ORDERED

将对其进行编译,但这将在BootstrappedElem隐藏类型构造函数ET ,以致于无法实现后面的部分。

整个非编译代码可以从https://raw.github.com/gist/4044281/0ce0336c40b277e59cece43dbadb9b94ce6efdaf/ordered.ml下载

我相信这可能是类型检查器中的错误。 我已将您的代码简化为以下示例:

module type ORDERED =
sig
  type t
  val compare : t -> t -> int
end


module type CARRY = sig
  module M : ORDERED
end

(* works *)
module HigherOrderFunctor
  (Make : functor (X : ORDERED) -> (CARRY with module M = X))
= struct
  module rec Base
    : (ORDERED with type t = string)
    = String
  and Other
    : (CARRY with module M = Base)
    = Make(Base)
end

(* does not work *)
module HigherOrderFunctor
  (Make : functor (X : ORDERED) -> (CARRY with module M = X))
= struct
  module rec Base
    : sig
      (* 'compare' seems dropped from this signature *)
      type t = string
      val compare : t -> t -> int
    end
    = String
  and Other
    : (CARRY with module M = (Base : sig type t = string val compare : t -> t -> int end))
    = Make(Base)
end

我不明白为什么第一个代码有效而第二个代码(看来等效)为什么不起作用。 我建议您稍等一下,看看专家是否提供了解释(Andreas?),然后考虑发送错误报告

在这种情况下,一种解决方案是首先绑定似乎处理不当的签名:

(* works again *)
module HigherOrderFunctor
  (Make : functor (X : ORDERED) -> (CARRY with module M = X))
= struct
  (* bind the problematic signature first *)
  module type S = sig
    type t = string
    val compare : t -> t -> int
  end

  module rec Base : S = String
  and Other : (CARRY with module M = Base) = Make(Base)
end

但是,这是不可能在你的设置,因为签名BootstrappedElem是相互递归BootstrappedHeap

一种解决方法是避免使用明显的with module ...构造并将其替换with type Elem.t = ...的简单类型相等:

module BootstrappedHeap
  (MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
  (Element : ORDERED) : (HEAP with module Elem = Element) =
struct
  module Elem = Element

  module rec BootstrappedElem :
  sig
    type t =
      | E
      | H of Elem.t * PrimH.heap
    val compare : t -> t -> int
  end =
  struct
    type t =
      | E
      | H of Elem.t * PrimH.heap
    let compare t1 t2 = match t1, t2 with
      | H (x, _), H (y, _) -> Elem.compare x y
      | _ -> failwith "unreachable"
  end
  and PrimH : (HEAP with type Elem.t = BootstrappedElem.t) =
    MakeH(BootstrappedElem)

  type heap

  let empty = failwith "not implemented"
  let insert = failwith "not implemented"
  let find_min = failwith "not implemented"
  let delete_min = failwith "not implemented"
end

您也可避免相互递归和定义都BootstrappedElemBootstrappedHeap在一个递归结,通过定义BootstrappedElem递归 BootstrappedHeap

module BootstrappedHeap
  (MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
  (Element : ORDERED) : (HEAP with module Elem = Element) =
struct
  module rec BootstrappedHeap : sig
    module Elem : sig
      type t = E | H of Element.t * BootstrappedHeap.heap
      val compare : t -> t -> int
    end        
    include (HEAP with module Elem := Elem)
  end = struct
    module Elem = struct
      type t = E | H of Element.t * BootstrappedHeap.heap
      let compare t1 t2 = match t1, t2 with
        | H (x, _), H (y, _) -> Element.compare x y
        | _ -> failwith "unreachable"
    end
    include (MakeH(Elem) : HEAP with module Elem := Elem)
  end

  module Elem = Element

  type heap

  let empty = failwith "not implemented"
  let insert = failwith "not implemented"
  let find_min = failwith "not implemented"
  let delete_min = failwith "not implemented"
end

这种风格自然符合您决定将Elem嵌入HEAP签名并with module ...使用with module ...进行优化的决定。 另一个解决方案是将HEAP定义为返回签名的函子,用作HEAP(Elem).S ,我想可以选择其他递归样式。 并不是说这样做会更好:我认为“抽象模块”样式更方便。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM