7

問題

私が抱えている問題の 1 つは、2 つのモジュールの型と値を新しい結合モジュールに持ち込むことです。例を挙げます。現在、次の2つの型シグネチャがあります

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

しかし、これには、上記の特定の 2 つのモジュールの場合、Ordered と Stack の両方が同じであるという問題がありますtype t(ただし、それぞれの意味は異なります)。Orderedandの元の定義はStacksコードの多くの部分で既に使用されているため、変更したくありませんが、元の 2 つのモジュールを機能させる別の定式化が見つかった場合は、それで問題ありません。

また、with演算子がここで関連している可能性があることも確認しましたが、目的の効果を生み出すために演算子をどのように使用する必要があるかについてはよくわかりませんでした。私が直面している問題は、2 つのモジュールのタイプtと実際に接続されていることです。'a tOrderedStacks

何か案は?

4

1 に答える 1

8

elemOrderedStack の再利用 (の代わりに)わずかに異なるタイプの順序付き定義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

冗長性のもう 1 つの原因は、パラメトリック型 からモノモルフィック に移行すること'a Stack.tですOrderedStack.t。2 つのタイプを同一視することはできず、まったく比較できないため、ここでは手動で変換する必要があります。

Stack(ポリモーフィック)からOrderedStack1 つの中間スタック (モノモーフィック) への移動を分解できることに注意してください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

2 回目の編集

Stackさて、私は/MonoStackブリッジをもたらすために次の解決策を思いつきました。しかし、率直に言って、これはハックであり、良い考えではないと思います。

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 に答える