1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
(Introduced in Objective Caml 3.07)
% TODO: relaxed syntax
\begin{syntax}
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 }
\end{syntax}
Recursive module definitions, introduced by the @"module rec"@ \ldots
@"and"@ \ldots\ construction, generalize regular module definitions
@'module' module-name '=' module-expr@ and module specifications
@'module' module-name ':' module-type@ by allowing the defining
@module-expr@ and the @module-type@ to refer recursively to the module
identifiers being defined. A typical example of a recursive module
definition is:
\begin{caml_example*}{verbatim}
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) -> Stdlib.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)
\end{caml_example*}
It can be given the following specification:
\begin{caml_example*}{signature}
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
\end{caml_example*}
This is an experimental extension of OCaml: the class of
recursive definitions accepted, as well as its dynamic semantics are
not final and subject to change in future releases.
Currently, the compiler requires that all dependency cycles between
the recursively-defined module identifiers go through at least one
``safe'' module. A module is ``safe'' if all value definitions that
it contains have function types @typexpr_1 '->' typexpr_2@. Evaluation of a
recursive module definition proceeds by building initial values for
the safe modules involved, binding all (functional) values to
@'fun' '_' '->' 'raise' @"Undefined_recursive_module". The defining
module expressions are then evaluated, and the initial values
for the safe modules are replaced by the values thus computed. If a
function component of a safe module is applied during this computation
(which corresponds to an ill-founded recursive definition), the
"Undefined_recursive_module" exception is raised at runtime:
\begin{caml_example}{verbatim}
module rec M: sig val f: unit -> int end = struct let f () = N.x end
and N:sig val x: int end = struct let x = M.f () end
\end{caml_example}
If there are no safe modules along a dependency cycle, an error is raised
\begin{caml_example}{verbatim}[error]
module rec M: sig val x: int end = struct let x = N.y end
and N:sig val x: int val y:int end = struct let x = M.x let y = 0 end
\end{caml_example}
Note that, in the @specification@ case, the @module-type@s must be
parenthesized if they use the @'with' mod-constraint@ construct.
|