summaryrefslogtreecommitdiff
path: root/manual/src/refman/extensions/generalizedopens.etex
blob: 0a02e1920959bd8409f6804bae9f70a413bd40ac (plain)
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
(Introduced in 4.08)

\begin{syntax}
definition:
      ...
   |  'open'  module-expr
   |  'open!' module-expr
;
specification:
      ...
   |  'open'  extended-module-path
   |  'open!' extended-module-path
;
expr:
       ...
     | 'let' 'open'  module-expr 'in' expr
     | 'let' 'open!' module-expr 'in' expr
;
\end{syntax}


This extension makes it possible to open any module expression in
module structures and expressions. A similar mechanism is also available
inside module types, but only for extended module paths (e.g. "F(X).G(Y)").

For instance, a module can be constrained when opened with

\begin{caml_example*}{verbatim}[error]
module M = struct let x = 0 let hidden = 1 end
open (M:sig val x: int end)
let y = hidden
\end{caml_example*}


Another possibility is to immediately open the result of a functor application

\begin{caml_example}{verbatim}
  let sort (type x) (x:x list) =
    let open Set.Make(struct type t = x let compare=compare end) in
    elements (of_list x)
\end{caml_example}

Going further, this construction can introduce local components inside a
structure,

\begin{caml_example}{verbatim}
module M = struct
  let x = 0
  open! struct
    let x = 0
    let y = 1
  end
  let w = x + y
end
\end{caml_example}

One important restriction is that types introduced by @'open' 'struct' ...
'end'@ cannot appear in the signature of the enclosing structure, unless they
are defined equal to some non-local type.
So:

\begin{caml_example}{verbatim}
module M = struct
  open struct type 'a t = 'a option = None | Some of 'a end
  let x : int t = Some 1
end
\end{caml_example}
is OK, but:

\begin{caml_example}{verbatim}[error]
module M = struct
  open struct type t = A end
  let x = A
end
\end{caml_example}
is not because "x" cannot be given any type other than "t", which only exists
locally. Although the above would be OK if "x" too was local:

\begin{caml_example}{verbatim}
module M: sig end = struct
  open struct
  type t = A
  end
  [@@@ellipsis]
  open struct let x = A end
  [@@@ellipsis]
end
\end{caml_example}

Inside signatures, extended opens are limited to extended module paths,
\begin{caml_example}{verbatim}
module type S = sig
  module F: sig end -> sig type t end
  module X: sig end
  open F(X)
  val f: t
end
\end{caml_example}

and not

\begin{verbatim}
  open struct type t = int end
\end{verbatim}

In those situations, local substitutions(see \ref{ss:local-substitution})
can be used instead.

Beware that this extension is not available inside class definitions:

\begin{verbatim}
class c =
  let open Set.Make(Int) in
  ...
\end{verbatim}