Sur*_*tor 7 ocaml types module signature
我遇到的一个问题是将两个模块的类型和值带入一个新的组合模块.我举个例子.目前我有以下两种类型的签名
module type Ordered =
sig
type t (* the type of elements which have an order *)
val eq : t * t -> bool
val lt : t * t -> bool
val leq : t * t -> bool
end
module type Stack =
sig
exception Empty
type 'a t (* the type of polymorphic stacks *)
val empty : 'a t
val isEmpty : 'a t -> bool
val cons : 'a * 'a t -> 'a t
val head : 'a t -> 'a
val tail : 'a t -> 'a t
end
Run Code Online (Sandbox Code Playgroud)
我想创建一个"按顺序排列基本元素的堆栈"模块,即
module type OrderedStack =
sig
exception Empty
type elem (* the type of the elements in the stack *)
val eq : elem * elem -> bool
val lt : elem * elem -> bool
val leq : elem * elem -> bool
type t (* the type of monomorphic stacks *)
val empty : t
val isEmpty : t -> bool
val cons : elem * t -> t
val head : t -> elem
val tail : t -> t
end
Run Code Online (Sandbox Code Playgroud)
到这里,一切都很好,整洁.但现在,我想编写一个带有Ordered模块和Stack模块并生成OrderedStack模块的仿函数.就像是
module My_functor (Elem : Ordered) (St : Stack): OrderedStack =
struct
exception Empty
type elem = Elem.t
let eq = Elem.eq
let lt = Elem.lt
let leq = Elem.leq
type t = elem St.t
let empty = St.empty
let isEmpty = St.isEmpty
let cons = St.cons
let head = St.head
let tail = St.tail
end
Run Code Online (Sandbox Code Playgroud)
这正是我想要的,也是正确的.但它看起来像是一个可怕的键盘浪费.
My_functor上面有一个更紧凑的方式吗?
我已经看到了include我可以编写类似的指令:
module my_functor (Elem : Ordered) (St : Stack): OrderedStack =
struct
include Elem
include St
end
Run Code Online (Sandbox Code Playgroud)
但是这有一个问题,对于我上面特定的两个模块,Ordered和Stack都有相同的type t(尽管它们在每个模块中意味着不同的东西).我不希望改变的原始定义Ordered,并Stacks为他们在代码中的许多地方已经使用,但如果你找到一个替代配方原来的两个模块,使得它的工作,这很好.
我也看到with操作员在这里可能是相关的,但我无法弄清楚如何使用它来产生所需的效果.我现在面临的问题是,该类型t和'a t两个模块的Ordered和Stacks实际连接和.
有任何想法吗?
OrderedStack重用有序定义,类型略有不同(elem而不是t).这是冗余的原因.
您可以OrderedStack直接重复使用此签名Ordered:
module type OrderedStack = sig
module Elem : Ordered
type t
val empty : t
val isEmpty : t -> bool
val cons : Elem.t * t -> t
val head : t -> Elem.t
val tail : t -> t
end
Run Code Online (Sandbox Code Playgroud)
另一个冗余来源是您从参数类型移动'a Stack.t到单形的事实OrderedStack.t.这两种类型不能相提并论,它们根本不具有可比性,因此必须在这里手工翻译.
需要注意的是,你可以从分解(多态)移动Stack到OrderedStack到一个中间堆(单态)MonoStack:
module type MonoStack = sig
type elem
type t
val empty : t
val isEmpty : t -> bool
val cons : elem * t -> t
val head : t -> elem
val tail : t -> t
end
module type OrderedStack = sig
module Elem : Ordered
module Stack : MonoStack with type elem = Elem.t
end
Run Code Online (Sandbox Code Playgroud)
编辑
如果您不喜欢使用子模块的额外间接,这会增加一些语法负担,则可以包含模块而不是链接到它们.但正如你所注意到的那样,问题就是名称冲突.从OCaml 3.12开始,我们的工具集中有一个新的构造,它允许重命名签名的类型组件以避免冲突.
module type OrderedStack = sig
type elem
include Ordered with type t := elem
include MonoStack with type elem := elem
end
Run Code Online (Sandbox Code Playgroud)
第二次编辑
好的,我想出了以下解决方案来带来Stack/ MonoStackbridge.但坦率地说,这是一个黑客,我不认为这是一个好主意.
module type PolyOrderedStack = sig
module Elem : Ordered
type t
type 'a const = t
module Stack : Stack with type 'a t = 'a const
end
(* 3.12 only *)
module type PolyOrderedStack = sig
type elem
include Ordered with type t := elem
type t
type 'a const = t
include Stack with type 'a t := 'a const
end
Run Code Online (Sandbox Code Playgroud)