(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 例外が発生します。