Functional programming 实施冈崎';为什么';它不编译吗?

Functional programming 实施冈崎';为什么';它不编译吗?,functional-programming,ocaml,functor,Functional Programming,Ocaml,Functor,(可以在中找到一个最小的非编译示例,请参阅下面的更多背景。) 我试图实现冈崎纯功能数据结构第10章中介绍的自举堆。下面是我的非编译代码的简化版本 我们要实现具有以下签名的堆: 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

(可以在中找到一个最小的非编译示例,请参阅下面的更多背景。)

我试图实现冈崎纯功能数据结构第10章中介绍的自举堆。下面是我的非编译代码的简化版本

我们要实现具有以下签名的堆:

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 BootstrappedHeap
  (MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
  (Element : ORDERED) : (HEAP with module Elem = Element)
当一个数据结构的实现依赖于同类数据结构的另一个实现时,我们说它是自举的。因此,我们有这样一个堆(实际实现并不重要):

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

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 BootstrappedHeap
  (MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
  (Element : ORDERED) : (HEAP with module Elem = Element)
所以我们可以这样使用它:

module StringHeap = BootstrappedHeap(SomeHeap)(String)
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
根据Okasaki的说法,BootstrappedHeap的实现如下:

module StringHeap = BootstrappedHeap(SomeHeap)(String)
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行就是第52行

and PrimH : (HEAP with module Elem = BootstrappedElem) =
我认为
BootstrappedElem
确实实现了
ORDERED
,因为它同时具有
t
compare
,但我不明白编译器为什么找不到
compare
函数

将BootstrappedElem的签名更改为

module rec BootstrappedElem : ORDERED
将进行编译,但这将在
BootstrappedElem
中隐藏类型构造函数
E
T
,从而无法实现后面的部分


整个非编译代码可以在

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

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
我不明白为什么第一个代码有效,而第二个(看起来相当)无效。我建议你等一下看专家是否有解释(安德烈亚斯?),然后考虑发送。

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

(* 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
但是,这在您的设置中是不可能的,因为
bootstrappedlem
的签名与
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
一种解决方法是避免使用module…构造明显微妙的
,并将其替换为使用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
您还可以通过在递归
BootstrappedHeap
中定义
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
定义为一个返回签名的函子,用作
HEAP(Elem).S
,我想可以选择不同的递归样式。并不是说这会更好:我认为“抽象模块”样式更方便。

非常感谢!我确实认为这看起来很像一个编译器错误。如果有更多的人可以确认,我会报告这个错误。