6.10 モジュール型

6.10.1. 単純な型式
6.10.2. シグネチャ
6.10.3. with 演算子

モジュール型はモジュールにおける型式で、モジュールの概形と型特性を規定します。

module-type ::= modtype-path
| sig { specification [ ;; ] } end
| functor ( module-name : module-type ) -> module-type
| module-type with mod-constraint { and mod-constraint }
| ( module-type )
mod-constraint ::= type [ type-parameters ] typeconstr-name = typexpr
| module module-path = extended-module-path
specification ::= val value-name : typexpr
| external value-name : typexpr = external-declaration
| type-definition
| exception constr-decl
| class-specification
| classtype-definition
| module module-name : module-type
| module module-name { ( module-name : module-type ) } : module-type
| module type modtype-name
| module type modtype-name = module-type
| open module-path
| include module-type

6.10.1 単純な型式

modtype-pathmodtype-path という名前に束縛されたモジュール型と等価です。 式 ( module-type )module-type と同一の型を表します。

6.10.2 シグネチャ

シグネチャはストラクチャの型仕様です。 シグネチャ sig ... end は値名、型名、例外、モジュール名、モジュール型名に対する仕様をまとめたものです。 ストラクチャがシグネチャに規定された名前(より多くの名前)に対する対する定義(実装)を提供し、その定義群がシグネチャで求められる型に適合する場合、そのストラクチャはシグネチャに適合します。

Caml Light との互換性のため、シグネチャ中の各仕様の後には ;; をつけることもできます。 ;; に特別な意味はありません。

値仕様

シグネチャ中で、値に対する仕様は val value-name : typexpr と書きます。 value-name は値の名前であり、 typexpr はその値に期待される型です。

external value-name : typexpr = external-declaration も同様ですが、その名前が external-declaration で規定される外部関数として実装されることを要求します。

型仕様

型に対する仕様は type typedef { and typedef } と書き、それぞれの定義は相互に再帰的な型の定義です。

シグネチャ中の型定義には、型等式 = typexpr や、型表現 = constr-decl ... や = { field-decl ... } を指定することができます。 型名の実装は(型等式が指定された場合)型等式に指定された型に適合し、(型表現が指定された場合)指定された型表現と同じ表現でなければなりません。 逆に言えば、そのシグネチャの利用者は(それがもし与えられていれば)その型等式や型表現を信頼することができるということです。 より正確には次のよっつの場合があります。

抽象型: 等式なし、表現なし

シグネチャで抽象型と定義された名前は、マッチするストラクチャでは(同一の個数の型パラメータを持つ)任意の定義を実装することができます。 型の実際の実装はストラクチャの利用者には隠蔽されています。 特に、その型がバリアント型やレコード型として実装されていた場合、利用者は対応する構成子やフィールドにアクセスすることができません。 型略記として実装されていた場合、その型の名前と略記の右辺との等価性はストラクチャの利用者には隠蔽されています。 利用者にはその型は他のどのような型とも適合しない、新しい型が生成されたように見えます。

型略記: 等式 = typexpr、表現なし

型名は typexpr に適合する型として実装されなければなりません。 ストラクチャの利用者にはその型が typexpr に適合することがわかります。

新規のバリアント型、レコード型: 等式なし、表現あり

型名は指定された構成子やフィールドと完全に一致するバリアント型やレコード型として実装されなければなりません。 ストラクチャの利用者は構成子やフィールドにアクセスすることができ、それらを使って値を作ったり値にアクセスしたりできます。 ただし、利用者にはその型は他のどのような型とも適合しない、新しい型が生成されたように見えます。

再 export されたバリアント型、レコード型: 等式あり、表現あり

これは前ふたつの場合が組み合わさったもので、型の表現が利用者から見え、新たな型は生成されません。

例外仕様

シグネチャ中の、 exception constr-decl という仕様は、それにマッチするストラクチャがこの定義で指定された名前と引数を持つ例外を提供し、その例外がストラクチャの利用者全員から利用可能あることを要求します。

クラス仕様

シグネチャ中には、 class class-spec { and class-spec } として、相互再帰的なクラス名の定義を並べ、複数のクラスの仕様を書くことができます。

クラスの仕様については、 6.9.4 節「クラス仕様 」により正確に説明されています。

クラス型仕様

シグネチャ中に、 class type classtype-def { and classtype-def } として、相互再帰的なクラス型の名前を並べることで、複数のクラス型に対する仕様を書くことができます。 クラス型の仕様については 6.9.5 節「クラス型定義 」により詳しく説明されています。

モジュール仕様

シグネチャ中でモジュール要素の仕様は module module-name : module-type と書きます。 module-name はモジュール要素の名前で、 module-type はそれに期待される型です。 モジュールは任意の深さに入れ子にすることができます。 特に、ファンクタはストラクチャの構成要素となることができ、シグネチャの構成要素のファンクタ型となることができます。

ファンクタであるようなモジュール構成要素を書くのに、

module module-name : functor ( name1 : module-type1 ) -> ... -> module-type

と書く代わりに次のように書くことができます。

module module-name ( name1 : module-type1 ) ... ( namen : module-typen ) : module-type

モジュール型仕様

シグネチャのモジュール型要素は、マニフェストモジュール型か抽象モジュール型として書くことができます。

抽象モジュール型仕様 module type modtype-name では、 modtype-name がシグネチャにマッチする任意のモジュールとして実装することができますが、そのモジュール型の実装はシグネチャの利用者に隠蔽されます。

マニフェストモジュール型仕様 module type modtype-name = module-type では対応するシグネチャ中で modtype-name がモジュール型 module-type により実装されることを要求し、 modtype-namemodule-type の等価性がシグネチャの利用者にわかるようになっいています。

モジュールパスの open

シグネチャ中の式 open module-path はどのような要素も規定しません。 この式は単にシグネチャ内の後続する要素の構文解析に影響するだけで、 module-path の表すモジュールの構成要素がパス経由の module-path ではなく、単純名の name でアクセスできるようになります。 open のスコープはシグネチャ式の終端で終了します。

シグネチャの include

シグネチャ中の式 include module-typemodule-type の表すシグネチャを字面上で取り込みます。 これは、 include されたシグネチャの要素が include のあった場所にそのままコピーされたような振舞いになります。 module-type は、ファンクタではなく、シグネチャを参照するモジュール型でなければなりません。

ファンクタ型

モジュール型式 functor ( module-name : module-type1 ) -> module-type2 はファンクタ(モジュールからモジュールへの関数)の型であり、このファンクタは型 module-type1 のモジュールを引数として取り、 module-type2 を結果として返します。 モジュール型 module-type2 では module-name を使ってファンクタの実引数の構成要素にアクセスすることができます。 ファンクタの取る引数の型には何の制約もありません。 特に、ファンクタは別のファンクタを引数として取ることができます(「高階」ファンクタ)。

6.10.3 with 演算子

module-type がシグネチャをあらわすとき、式 module-type with mod-constraint { and mod-constraint } は、 module-type に予約語 with に続く制約で指定した型仕様に対して型等式を追加したシグネチャを表します。 type [type-parameters] typeconstr = typexpr という制約は、制約の追加されるシグネチャの typeconstr という型要素に = typexpr という型等式を追加します。 module module-path = extended-module-path という制約は、 module-path で表される下位ストラクチャのすべての型要素に型等式を追加し、それらの型要素が extended-module-path で表されるストラクチャ内の対応する型要素と等しくなるようにします。

例えば、モジュール型名 S が次のシグネチャに束縛されているとき、

sig type t module M: (sig type u end) end

S with type t = int は次のシグネチャを表します。

sig type t=int module M: (sig type u end) end

そして、 S with module M = N は次のシグネチャを表します。

sig type t module M: (sig type u=N.u end) end

S の引数をふたつ取り、その型要素 t を共有するファンクタは次のように書けます。

functor (A: S) (B: S with type t = A.t) ...

制約は左から右へ追加されます。 制約がすべて適用された結果のシグネチャは、制約を適用する前のシグネチャの部分型にならなければなりません。 したがって、 with 演算子はシグネチャの型要素に情報を追加することだけができ、情報を取り除くことはできないのです。