(OCaml 3.07 〜)
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 の実験的な拡張です。受け入れられる再帰的定義のクラスは、その動的な意味論も含め、最終的なものではなく将来変更されるかもしれません。
現在の実装では、再帰的に定義されたモジュール識別子の依存関係の輪が、最低でもひとつは「安全な」モジュールを含むことを要求しています。モジュール中のすべての値の定義が関数型 typexpr1 -> typexpr2
を持つとき、そのモジュールは「安全」である、と言います。再帰モジュールの定義は、そこに含まれる安全なモジュール内の(関数)値に初期値として fun _ -> raise Undefined_recursive_module
を束縛することにより進められます。その次に、定義中のモジュール内の式を評価し、それによって計算された値で安全なモジュール内の束縛に与えられた初期値が置き換えられます。安全なモジュール内の関数が値の計算中に適用されると(これは ill-founded な再帰定義にあたります)、 Undefined_recursive_module
例外が発生します。