Tia*_*Cui 5 ocaml functional-programming functor
(可以在https://gist.github.com/4044467找到最小的非编译示例,请参阅下面的更多背景.)
我正在尝试实现Okasaki 纯功能数据结构第10章中介绍的Bootstrapped Heaps.以下是我的非编译代码的简化版本.
我们要实现一个具有以下签名的堆:
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
Run Code Online (Sandbox Code Playgroud)
我们说当数据结构的实现依赖于同一种数据结构的另一种实现时,它就会被引导.所以我们有这样的堆(实际的实现并不重要):
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
Run Code Online (Sandbox Code Playgroud)
然后,我们要实现的引导堆(可以依赖于任何堆实现)应该具有以下签名:
module BootstrappedHeap
(MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
(Element : ORDERED) : (HEAP with module Elem = Element)
Run Code Online (Sandbox Code Playgroud)
所以我们可以像这样使用它:
module StringHeap = BootstrappedHeap(SomeHeap)(String)
Run Code Online (Sandbox Code Playgroud)
根据Okasaki的说法,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
Run Code Online (Sandbox Code Playgroud)
但这不是编译!错误消息是:
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
Run Code Online (Sandbox Code Playgroud)
线52是线
and PrimH : (HEAP with module Elem = BootstrappedElem) =
Run Code Online (Sandbox Code Playgroud)
我认为BootstrappedElem确实实现了,ORDERED因为它有两个t和compare,但我没有看到为什么编译器无法找到该compare功能.
将BootstrappedElem的签名更改为
module rec BootstrappedElem : ORDERED
Run Code Online (Sandbox Code Playgroud)
将使编译但这将隐藏式构造E,并T在BootstrappedElem使它不可能实现的后面部分.
整个非编译代码可以在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
Run Code Online (Sandbox Code Playgroud)
我不明白为什么第一个代码工作,第二个(似乎等效)没有.我建议你稍等一下,看看专家是否有解释(安德烈亚斯?),然后考虑发送错误报告.
在这种情况下,解决方案是首先绑定看似错误处理的签名:
(* 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
Run Code Online (Sandbox Code Playgroud)
但是,这在您的设置中是不可能的,因为签名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
Run Code Online (Sandbox Code Playgroud)
您也可避免相互递归和定义都BootstrappedElem和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
Run Code Online (Sandbox Code Playgroud)
这种风格自然与您Elem在HEAP签名中嵌入和使用with module ...细化的决定相对应.另一个解决方案是定义HEAP为一个返回签名的仿函数,用作HEAP(Elem).S,我想可以选择一个不同的递归样式.并不是说这会更好:我认为"抽象模块"风格更方便.