Module OCaml模块:将不同模块中的(互连)类型引入到新模块中 问题
我遇到的一个问题是将两个模块的类型和VAL合并到一个新的组合模块中。我举个例子。目前我有以下两种类型的签名Module OCaml模块:将不同模块中的(互连)类型引入到新模块中 问题,module,types,ocaml,signature,Module,Types,Ocaml,Signature,我遇到的一个问题是将两个模块的类型和VAL合并到一个新的组合模块中。我举个例子。目前我有以下两种类型的签名 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 = s
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
我想创建一个“基本元素排序的堆栈”模块,即
到目前为止,一切都很好和整洁。但现在,我想写一个函子,它接受一个有序模块和一个堆栈模块,并生成一个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和Stack都具有相同的类型t
(尽管它们在每个模块中的含义不同)。我不想改变有序的
和堆栈
的原始定义,因为它们已经在代码的许多部分中使用过,但是如果您为原始的两个模块找到一个替代公式,使其工作,那就好了
我也看到了这可能与此相关,但我不太清楚应该如何使用它来产生预期的效果。我面临的问题是,两个模块的类型t
和'at
是有序的
和堆栈
,并且实际上是连接在一起的
有什么想法吗?有序堆栈重用有序定义,使用稍微不同的类型(
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
冗余的另一个来源是,您从参数化类型('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
编辑
如果您不喜欢使用子模块的额外间接方式,这会增加一些语法负担,那么可以包括模块而不是链接到它们。但正如你所注意到的,问题在于名称冲突。从OCAML3.12开始,我们的工具集中有一个新的构造,它允许重命名签名的类型组件以避免冲突
module type OrderedStack = sig
type elem
include Ordered with type t := elem
include MonoStack with type elem := elem
end
第二次编辑
好的,我想出了下面的解决方案来实现堆栈
/单堆栈
桥。但坦率地说,这是一个黑客行为,我认为这不是一个好主意
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
我没有无缘无故地从多态性堆栈移动到单态。注意,在我的OrderedStack中,如果我使用堆栈类型
'a t
,我会有一个参数,而我没有。堆栈将是elem
类型元素的堆栈,即在OrderedStack中,Ordered类型和堆栈类型之间存在连接。所以,为了遵循您的分解思想,我很乐意直接使用Stack而不是MonoStack。但是,在OrderedStack类型的最后一行代码中,您将编写什么?您无法编写模块堆栈:类型为'a t=Elem.t
的堆栈…感谢涉及子模块的解决方案。它很整洁。只有一件事我不喜欢。在这个公式中,当我需要使用模块OS:OrderedStack
比较两个元素时,我必须编写OS.Elem.leq(x,y)
,而不是简单地编写感觉有点不自然的OS.leq(x,y)
。另外,如果我只想将某些东西放入堆栈,我会编写OS.stack.cons(x,s)
,而我想直接使用操作系统OS.cons(x,s)
。话虽如此,这将确保我停下来思考在比较元素或推动时使用的确切内部结构。(在3.12编辑中)很棒的东西!这正是我想要的,是的。我不知道那个构造。非常有趣。谢谢(现在唯一的问题是,我使用的是Godi,目前只有3.11.2版本。希望很快会更新。)没有,但请稍候。这是签名(模块类型)。我怎么写函子?我不能在模或函子中使用include
。好的,对于函子,我将使用子模。事实上,我越来越喜欢这个解决方案。包有点乱。单态性/多态性的事情仍然让我心烦意乱。应该有办法做到这一点。你的'a cons
想法解决了这个问题,但是,作为你自己,我发现黑客可能会导致核心变得模糊。我添加了一个OCaml 3.12解决方案,它允许你同时包含单堆栈
和有序
,而不是子模块。然而,我倾向于选择子模块解决方案——至少因为我还没有使用3.12。子模块的一个优点是,您可以轻松地将它们传递给其他函子:“哦,我需要构建堆栈中的一组元素”。@gasche是的,我也并没有3.12。我不希望匆忙地将代码更改为最近的语言更改,因为除非您有最先进的安装,否则它不会在其他机器上编译。是的,你说得对,我没有想过在函子中使用模块的一部分。相当整洁!
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