モジュール式はモジュールにおける値式で、モジュールに評価されます。 モジュール式はモジュール型で表現された仕様に対する実装です。
module-expr | ::= | module-path |
| | struct { definition [ ;; ] || expr ;; } end | |
| | functor ( module-name : module-type ) -> module-expr | |
| | module-expr ( module-expr ) | |
| | ( module-expr ) | |
| | ( module-expr : module-type ) | |
definition | ::= | let [ rec ] let-binding { and let-binding } |
| | external value-name : typexpr = external-declaration | |
| | type-definition | |
| | exception-definition | |
| | class-definition | |
| | classtype-definition | |
| | module module-name { ( module-name : module-type ) } [ : module-type ] = module-expr | |
| | module type modtype-name = module-type | |
| | open module-path | |
| | include module-expr |
module-path はその名前に束縛されたモジュールに評価されます。
(module-expr) は module-expr と同じモジュールに評価されます。
(module-expr : module-type) は、 module-expr の型が module-type の部分型であるかどうか、すなわち、 module-type で規定された要素がすべて module-expr で実装されてい、その実装が module-type の要求に合致しているかをチェックします。 式全体は module-expr と同じモジュールに評価されますが、 module-type に指定されていない要素はすべて隠蔽され、アクセスできなくなります。
ストラクチャ struct ... end は、値の名前、型名、例外、モジュール名、モジュール型の名前に対する定義を集めたものです。 各定義はストラクチャ内に現れた順に評価されます。 各定義により確立される束縛のスコープはストラクチャ全体にまで拡大されます。 そのため、ある定義で、同一のストラクチャ内で先に定義した名前を参照することができます。
トップレベルや Caml Lightとの互換性のために、定義の後ろには ;;
を付けられます。
;;
に特別な意味はありません。
また、さらに互換性のために、構成要素として expr ;; と書くこともできます。
これは let _ = expr を意味し、 expr は副作用のために評価されます。
このときの ;;
は省略できません。
値の定義 let [rec] let-binding { and let-binding } は let ... in ... 式(「局所定義 」参照)と同じく値の名前を束縛します。 束縛の左辺に現れる名前は対応する右辺の値に束縛されます。
external value-name : typexpr = external-declaration の値定義は、 value-name を external-declaration で指定された外部関数として実装[10]します。
例外は exception constr-decl、または exception constr-name = constr として定義します。
class class-binding { and class-binding } として、相互再帰的なクラスの名前から成る定義を書くことができます。 クラス定義については 6.9.3 節「クラス定義 」により正確に説明されています。
class type classtype-def { and classtype-def } として、相互再帰的なクラス型の名前の定義からなるクラス型の定義を書くことができます。クラス型の定義は 6.9.5 節「クラス型定義 」により正確に説明されています。
モジュール要素の定義の構文の基本形は module module-name = module-expr で、 module-expr を評価し、その結果を module-name に束縛します。
module module-name = (module-expr : module-type)
と書く代わりに
module module-name : module-type = module-expr
と書くこともできます。 また、
module module-name ( name1 module-type1) ... (namen
: module-typen
) = module-expr
は
module module-name = functor (name1 : module-type1) -> ... -> module-expr
と等価です。
モジュール型の定義は module type modtype-name = module-type と書き、 module-type の表すモジュール型に modtype-name を束縛します。
ストラクチャ内で open module-path としても何の要素も定義されず、名前も束縛されません。
この構文はストラクチャ内の後続する要素の構文解析に影響を与え、 module-path の表すモジュールの構成要素が、 module-path 経由ではなく、単純名で参照できるようにする効果しかありません。
open
のスコープはストラクチャ式の末尾で終了します。
モジュール中で include module-expr とすると、 module-expr の表すストラクチャ内のすべての定義が現在のストラクチャに再エクスポートされます。
例えば、識別子 S
が次のモジュールに束縛されているとき、
struct type t = int let x = 2 end
次のモジュール式
struct include S let y = (x + 1 : t) end
は下のモジュール式と等価になります。
struct type t = int let x = 2 let y = (x + 1 : t) end
open
と include
の違いは、 open
が単純に、 open
されたストラクチャの構成要素へ短かい名前でアクセスできるようにするだけで、現在のストラクチャには何の要素も定義しないのに対し、
include
は include
されたストラクチャの要素の定義を現在のストラクチャに追加するということです。
functor ( module-name : module-type) -> module-expr は module-type1 型のモジュールを引数に取るファンクタに評価されます。 module-expr は module-name の束縛された環境で評価され、その結果のモジュールを返します。 ファンクタの引数の型には何の制約もなく、特に、ファンクタが別のファンクタを引数に取ることもできます(高階ファンクタ)。
module-expr1 (module-expr2) は module-expr1 がファンクタに評価され、 module-expr2 がモジュールに評価され、そのファンクタをモジュールに適用します。 module-expr2 の型は module-expr1 の引数型として期待される型に適合しなければなりません。