7.9 再帰的モジュール (Recursive modules)

    definition ::=  ...                                                       
                 |   module rec module-name :  module-type =  module-expr   {
               and module-name:  module-type =  module-expr } 
 specification ::=  ...                                                       
                |   module rec module-name :  module-type  { and module-name: 
                module-type }                                

再帰的モジュール定義は、 'module rec' ... 'and' ... 構文で導入できますが, これは通常のモジュール定義 module module-name = module-expr と モジュール仕様 module module-name : module-type を、module-expr や module-type で定義途中のモジュール識別子を参照できるように一般化したものです。 典型的な再帰的モジュール定義は:

    module rec A : sig
                     type t = Leaf of string | Node of ASet.t
                     val compare: t -> t -> int
                   end
                 = struct
                     type t = Leaf of string | Node of ASet.t
                     let compare t1 t2 =
                       match (t1, t2) with
                         (Leaf s1, Leaf s2) -> Pervasives.compare s1 s2
                       | (Leaf _, Node _) -> 1
                       | (Node _, Leaf _) -> -1
                       | (Node n1, Node n2) -> ASet.compare n1 n2
                   end
        and ASet : Set.S with type elt = A.t
                 = Set.Make(A)

これには 次の仕様を与えることができます:

    module rec A : sig
                     type t = Leaf of string | Node of ASet.t
                     val compare: t -> t -> int
                   end
        and ASet : Set.S with type elt = A.t

これは Objective Caml の実験的な拡張です: 許可される再帰的定義のクラスは、その動的な意味論と同様に、最終的なものではなく将来のリリースで変更されるかもしれません。

今のところ、 コンパイラは 再帰的に定義されたモジュール識別子のあいだのすべての依存関係のサイクルが最低1つの「安全な」モジュールを通ることを要求します。 モジュールが安全であるとは、 モジュールが含んでいるすべての値定義が関数型 typexpr_1 -> typexpr_2 をもつことです。 再帰的モジュールの評価は 安全なモジュールの初期値を構築することで進行し, 全ての (関数)値 を fun _ -> raise Undefined_recursive_module に束縛します. その後にモジュール式全体が評価され,安全なモジュールの初期値がここで計算された値で置き換えられます. もしある安全なモジュールに含まれる関数がこの計算の途中で適用された場合 (これは ill-founded (FIXME:日本語訳) な再帰的定義に対応します)、 Undefined_recursive_module 例外が raise されます。