OCaml 模块:将(互连的)类型从不同模块引入新模块
问题
我遇到的一个问题是将两个模块的类型和值带入一个新的组合模块中。我举个例子。目前我有以下两种类型签名
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
,我想创建一个“基本元素已排序的堆栈”模块,即
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
到目前为止,一切都很好且整洁。但现在,我想编写一个函子,它接受 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
这正是我想要的并且是正确的。但这看起来非常浪费键盘。
我的问题
有没有更紧凑的方式来编写上面的 My_functor
?
我发现但无法付诸实践的内容
我已经看到了 include
指令,我可以在其中编写类似以下内容的内容:
module my_functor (Elem : Ordered) (St : Stack): OrderedStack =
struct
include Elem
include St
end
但这有一个问题,对于我上面特定的两个模块, Ordered 和堆栈具有相同的类型 t
(尽管它们各自的含义不同)。我不想更改 Ordered
和 Stacks
的原始定义,因为它们已经在代码的许多部分中使用,但是如果您找到原始两个的替代公式使其工作的模块,那很好。
我还看到 with
运算符 可能与这里相关,但我无法完全弄清楚应该如何使用它来产生所需的效果。我面临的问题是两个模块 Ordered
和 Stacks
的类型 t
和 'a t
和实际上已连接。
有什么想法吗?
The problem
One problem I'm having is bringing the types and vals of two module into a new combined module. I'll give an example. Currently I have the following two type signatures
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
and I'd like to create a module of "stacks for which the basic elements are ordered", i.e.
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
Up to here, everything is nice and neat. But now, I'd like to write a functor which takes an Ordered module and a Stack module and produces an OrderedStack module. Something like
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
This is exactly what I want and is correct. But it looks like an awful waste of keyboard.
My question
Is there a more compact way to write My_functor
above?
What I found out but couldn't put to work
I've seen the include
directive in which I could write something like:
module my_functor (Elem : Ordered) (St : Stack): OrderedStack =
struct
include Elem
include St
end
but this has the problem that, for my particular two modules above, both Ordered and Stack have the same type t
(although they mean different things in each of them). I'd prefer not to change the original definition of Ordered
and Stacks
as they are already used in many parts in the code but if you find an alternative formulation for the original two modules that makes it work, that's fine.
I've also seen that the with
operator may be relevant here but I couldn't quite work out how it should be used to produce the desired effect. The problem I'm facing is that the types t
and 'a t
of the two modules Ordered
and Stacks
and actually connected.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
OrderedStack 重用有序定义,但类型略有不同(
elem
而不是t
)。这是冗余的原因。您宁愿使用此
OrderedStack
签名,直接重用Ordered
:冗余的另一个来源是您从参数类型
'a Stack.t< /code>,到单态
OrderedStack.t
。这两种类型不能等同,根本没有可比性,所以这里需要手工翻译。请注意,您可以将从(多态)
Stack
到OrderedStack
的移动分解为一个中间堆栈,(单态)MonoStack
:编辑< /strong>
如果您不喜欢使用子模块的额外间接性(这会增加一些语法负担),则可以包含模块而不是链接到它们。但正如您所注意到的,问题在于名称冲突。从 OCaml 3.12 开始,我们的工具集中有一个新的构造,它允许重命名签名的类型组件以避免冲突。
第二次编辑
好的,我想出了以下解决方案来引入
Stack
/MonoStack
桥接器。但坦率地说,这是一种黑客行为,我认为这不是一个好主意。OrderedStack reuse Ordered definitions, with a slightly different type (
elem
instead oft
). This a cause of redundancy.You could rather use this
OrderedStack
signature directly reusingOrdered
:One other source of redundancy is the fact that you move from a parametric type,
'a Stack.t
, to the monomorphicOrderedStack.t
. The two types cannot be equated, they are not at all comparable, so there necessarily a translation to make by hand here.Note that you could decompose the move from (polymorphic)
Stack
toOrderedStack
into one intermediary stack, (monomorphic)MonoStack
:Edit
If you don't like the additional indirection of using submodules, which can add some syntactic burden, it is possible of including the modules instead of linking to them. But the problem, as you have noticed, are the name conflict. Starting from OCaml 3.12, we have a new construct in our toolset which allows to rename type components of signatures to avoid conflicts.
Second Edit
Okay, I came up with the following solution to bring the
Stack
/MonoStack
bridge. But quite frankly, it's a hack and I don't think it's a good idea.