Module OCaml模块:将不同模块中的(互连)类型引入到新模块中 问题

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

我遇到的一个问题是将两个模块的类型和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 =
 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