7

问题

我遇到的一个问题是将两个模块的类型和值带入一个新的组合模块。我举个例子。目前我有以下两种类型签名

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 和 Stack 都有相同的type t(尽管它们在每个模块中意味着不同的东西)。我不希望更改 and 的原始定义,Ordered因为Stacks它们已经在代码中的许多部分中使用,但是如果您找到原始两个模块的替代公式使其工作,那很好。

我还看到with操作符在这里可能是相关的,但我不太清楚应该如何使用它来产生所需的效果。我面临的问题是两个模块的类型t和实际连接。'a tOrderedStacks

有任何想法吗?

4

1 回答 1

8

OrderedStack 重用 Ordered 定义,类型稍有不同(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. 这两种类型不能划等号,根本没有可比性,所以这里一定要手工翻译。

请注意,您可以将移动从 (polymorphic) 分解StackOrderedStack一个中间堆栈 (monomorphic) 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

编辑

如果您不喜欢使用子模块的额外间接性,这会增加一些语法负担,则可以包含模块而不是链接到它们。但是,正如您所注意到的,问题在于名称冲突。从 OCaml 3.12 开始,我们的工具集中有一个新结构,它允许重命名签名的类型组件以避免冲突。

module type OrderedStack = sig
  type elem
  include Ordered with type t := elem
  include MonoStack with type elem := elem
end

第二次编辑

好的,我想出了以下解决方案来带Stack/MonoStack桥。但坦率地说,这是一个 hack,我认为这不是一个好主意。

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
于 2011-01-29T21:15:37.240 回答