1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
2
"http://www.w3.org/TR/REC-html40/loose.dtd">
6
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
7
<META name="GENERATOR" content="hevea 1.06-7 of 2001-11-14">
12
<BODY TEXT=black BGCOLOR=white>
13
<A HREF="manual003.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
14
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
15
<A HREF="manual005.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
17
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
18
<TR><TD BGCOLOR="#2de52d"><DIV ALIGN=center><TABLE>
19
<TR><TD><A NAME="htoc12"><B><FONT SIZE=6>Chapter 2</FONT></B></A></TD>
20
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=6>The module system</FONT></B></TD>
21
</TR></TABLE></DIV></TD>
22
</TR></TABLE> <A NAME="c:moduleexamples"></A>
24
This chapter introduces the module system of Objective Caml.<BR>
26
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
27
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
28
<TR><TD><A NAME="htoc13"><B><FONT SIZE=5>2.1</FONT></B></A></TD>
29
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Structures</FONT></B></TD>
30
</TR></TABLE></DIV></TD>
33
A primary motivation for modules is to package together related
34
definitions (such as the definitions of a data type and associated
35
operations over that type) and enforce a consistent naming scheme for
36
these definitions. This avoids running out of names or accidentally
37
confusing names. Such a package is called a <EM>structure</EM> and
38
is introduced by the <TT>struct</TT>...<TT>end</TT> construct, which contains an
39
arbitrary sequence of definitions. The structure is usually given a
40
name with the <TT>module</TT> binding. Here is for instance a structure
41
packaging together a type of priority queues and their operations:
42
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module PrioQueue =
45
type 'a queue = Empty | Node of priority * 'a * 'a queue * 'a queue
47
let rec insert queue prio elt =
49
Empty -> Node(prio, elt, Empty, Empty)
50
| Node(p, e, left, right) ->
52
then Node(prio, elt, insert right p e, left)
53
else Node(p, e, insert right prio elt, left)
54
exception Queue_is_empty
55
let rec remove_top = function
56
Empty -> raise Queue_is_empty
57
| Node(prio, elt, left, Empty) -> left
58
| Node(prio, elt, Empty, right) -> right
59
| Node(prio, elt, (Node(lprio, lelt, _, _) as left),
60
(Node(rprio, relt, _, _) as right)) ->
62
then Node(lprio, lelt, remove_top left, right)
63
else Node(rprio, relt, left, remove_top right)
64
let extract = function
65
Empty -> raise Queue_is_empty
66
| Node(prio, elt, _, _) as queue -> (prio, elt, remove_top queue)
68
<FONT COLOR=maroon>module PrioQueue :
71
and 'a queue = Empty | Node of priority * 'a * 'a queue * 'a queue
73
val insert : 'a queue -> priority -> 'a -> 'a queue
74
exception Queue_is_empty
75
val remove_top : 'a queue -> 'a queue
76
val extract : 'a queue -> priority * 'a * 'a queue
78
</FONT></FONT></FONT></PRE>
79
Outside the structure, its components can be referred to using the
80
``dot notation'', that is, identifiers qualified by a structure name.
81
For instance, <TT>PrioQueue.insert</TT> in a value context is
82
the function <TT>insert</TT> defined inside the structure
83
<TT>PrioQueue</TT>. Similarly, <TT>PrioQueue.queue</TT> in a type context is the
84
type <TT>queue</TT> defined in <TT>PrioQueue</TT>.
85
<PRE><FONT COLOR=black>#<FONT COLOR=blue>PrioQueue.insert PrioQueue.empty 1 "hello";;
86
<FONT COLOR=maroon>- : string PrioQueue.queue =
87
PrioQueue.Node (1, "hello", PrioQueue.Empty, PrioQueue.Empty)
88
</FONT></FONT></FONT></PRE>
89
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
90
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
91
<TR><TD><A NAME="htoc14"><B><FONT SIZE=5>2.2</FONT></B></A></TD>
92
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Signatures</FONT></B></TD>
93
</TR></TABLE></DIV></TD>
96
Signatures are interfaces for structures. A signature specifies
97
which components of a structure are accessible from the outside, and
98
with which type. It can be used to hide some components of a structure
99
(e.g. local function definitions) or export some components with a
100
restricted type. For instance, the signature below specifies the three
101
priority queue operations <TT>empty</TT>, <TT>insert</TT> and <TT>extract</TT>, but not the
102
auxiliary function <TT>remove_top</TT>. Similarly, it makes the <TT>queue</TT> type
103
abstract (by not providing its actual representation as a concrete type).
104
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module type PRIOQUEUE =
106
type priority = int (* still concrete *)
107
type 'a queue (* now abstract *)
109
val insert : 'a queue -> int -> 'a -> 'a queue
110
val extract : 'a queue -> int * 'a * 'a queue
111
exception Queue_is_empty
113
<FONT COLOR=maroon>module type PRIOQUEUE =
118
val insert : 'a queue -> int -> 'a -> 'a queue
119
val extract : 'a queue -> int * 'a * 'a queue
120
exception Queue_is_empty
122
</FONT></FONT></FONT></PRE>
123
Restricting the <TT>PrioQueue</TT> structure by this signature results in
124
another view of the <TT>PrioQueue</TT> structure where the <TT>remove_top</TT>
125
function is not accessible and the actual representation of priority
127
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module AbstractPrioQueue = (PrioQueue : PRIOQUEUE);;
128
<FONT COLOR=maroon>module AbstractPrioQueue : PRIOQUEUE
130
<FONT COLOR=black>#<FONT COLOR=blue><U>AbstractPrioQueue.remove_top</U>;;
131
<FONT COLOR=maroon>Unbound value AbstractPrioQueue.remove_top
133
<FONT COLOR=black>#<FONT COLOR=blue>AbstractPrioQueue.insert AbstractPrioQueue.empty 1 "hello";;
134
<FONT COLOR=maroon>- : string AbstractPrioQueue.queue = <abstr>
135
</FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></PRE>
136
The restriction can also be performed during the definition of the
139
module PrioQueue = (struct ... end : PRIOQUEUE);;
140
</PRE>An alternate syntax is provided for the above:
142
module PrioQueue : PRIOQUEUE = struct ... end;;
144
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
145
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
146
<TR><TD><A NAME="htoc15"><B><FONT SIZE=5>2.3</FONT></B></A></TD>
147
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Functors</FONT></B></TD>
148
</TR></TABLE></DIV></TD>
151
Functors are ``functions'' from structures to structures. They are used to
152
express parameterized structures: a structure <I>A</I> parameterized by a
153
structure <I>B</I> is simply a functor <I>F</I> with a formal parameter
154
<I>B</I> (along with the expected signature for <I>B</I>) which returns
155
the actual structure <I>A</I> itself. The functor <I>F</I> can then be
156
applied to one or several implementations <I>B</I><SUB><FONT SIZE=2>1</FONT></SUB> ...<I>B</I><SUB><FONT SIZE=2><I>n</I></FONT></SUB>
157
of <I>B</I>, yielding the corresponding structures
158
<I>A</I><SUB><FONT SIZE=2>1</FONT></SUB> ...<I>A</I><SUB><FONT SIZE=2><I>n</I></FONT></SUB>.<BR>
160
For instance, here is a structure implementing sets as sorted lists,
161
parameterized by a structure providing the type of the set elements
162
and an ordering function over this type (used to keep the sets
164
<PRE><FONT COLOR=black>#<FONT COLOR=blue>type comparison = Less | Equal | Greater;;
165
<FONT COLOR=maroon>type comparison = Less | Equal | Greater
167
<FONT COLOR=black>#<FONT COLOR=blue>module type ORDERED_TYPE =
170
val compare: t -> t -> comparison
172
<FONT COLOR=maroon>module type ORDERED_TYPE = sig type t val compare : t -> t -> comparison end
174
<FONT COLOR=black>#<FONT COLOR=blue>module Set =
175
functor (Elt: ORDERED_TYPE) ->
178
type set = element list
184
match Elt.compare x hd with
185
Equal -> s (* x is already in s *)
186
| Less -> x :: s (* x is smaller than all elements of s *)
187
| Greater -> hd :: add x tl
192
match Elt.compare x hd with
193
Equal -> true (* x belongs to s *)
194
| Less -> false (* x is smaller than all elements of s *)
195
| Greater -> member x tl
197
<FONT COLOR=maroon>module Set :
198
functor (Elt : ORDERED_TYPE) ->
201
and set = element list
203
val add : Elt.t -> Elt.t list -> Elt.t list
204
val member : Elt.t -> Elt.t list -> bool
206
</FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></PRE>
207
By applying the <TT>Set</TT> functor to a structure implementing an ordered
208
type, we obtain set operations for this type:
209
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module OrderedString =
212
let compare x y = if x = y then Equal else if x < y then Less else Greater
214
<FONT COLOR=maroon>module OrderedString :
215
sig type t = string val compare : 'a -> 'a -> comparison end
217
<FONT COLOR=black>#<FONT COLOR=blue>module StringSet = Set(OrderedString);;
218
<FONT COLOR=maroon>module StringSet :
220
type element = OrderedString.t
221
and set = element list
223
val add : OrderedString.t -> OrderedString.t list -> OrderedString.t list
224
val member : OrderedString.t -> OrderedString.t list -> bool
227
<FONT COLOR=black>#<FONT COLOR=blue>StringSet.member "bar" (StringSet.add "foo" StringSet.empty);;
228
<FONT COLOR=maroon>- : bool = false
229
</FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></PRE>
230
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
231
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
232
<TR><TD><A NAME="htoc16"><B><FONT SIZE=5>2.4</FONT></B></A></TD>
233
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Functors and type abstraction</FONT></B></TD>
234
</TR></TABLE></DIV></TD>
237
As in the <TT>PrioQueue</TT> example, it would be good style to hide the
238
actual implementation of the type <TT>set</TT>, so that users of the
239
structure will not rely on sets being lists, and we can switch later
240
to another, more efficient representation of sets without breaking
241
their code. This can be achieved by restricting <TT>Set</TT> by a suitable
243
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module type SETFUNCTOR =
244
functor (Elt: ORDERED_TYPE) ->
246
type element = Elt.t (* concrete *)
247
type set (* abstract *)
249
val add : element -> set -> set
250
val member : element -> set -> bool
252
<FONT COLOR=maroon>module type SETFUNCTOR =
253
functor (Elt : ORDERED_TYPE) ->
258
val add : element -> set -> set
259
val member : element -> set -> bool
262
<FONT COLOR=black>#<FONT COLOR=blue>module AbstractSet = (Set : SETFUNCTOR);;
263
<FONT COLOR=maroon>module AbstractSet : SETFUNCTOR
265
<FONT COLOR=black>#<FONT COLOR=blue>module AbstractStringSet = AbstractSet(OrderedString);;
266
<FONT COLOR=maroon>module AbstractStringSet :
268
type element = OrderedString.t
269
and set = AbstractSet(OrderedString).set
271
val add : element -> set -> set
272
val member : element -> set -> bool
275
<FONT COLOR=black>#<FONT COLOR=blue>AbstractStringSet.add "gee" AbstractStringSet.empty;;
276
<FONT COLOR=maroon>- : AbstractStringSet.set = <abstr>
277
</FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></PRE>
278
In an attempt to write the type constraint above more elegantly,
279
one may wish to name the signature of the structure
280
returned by the functor, then use that signature in the constraint:
281
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module type SET =
286
val add : element -> set -> set
287
val member : element -> set -> bool
289
<FONT COLOR=maroon>module type SET =
294
val add : element -> set -> set
295
val member : element -> set -> bool
298
<FONT COLOR=black>#<FONT COLOR=blue>module WrongSet = (Set : functor(Elt: ORDERED_TYPE) -> SET);;
299
<FONT COLOR=maroon>module WrongSet : functor (Elt : ORDERED_TYPE) -> SET
301
<FONT COLOR=black>#<FONT COLOR=blue>module WrongStringSet = WrongSet(OrderedString);;
302
<FONT COLOR=maroon>module WrongStringSet :
304
type element = WrongSet(OrderedString).element
305
and set = WrongSet(OrderedString).set
307
val add : element -> set -> set
308
val member : element -> set -> bool
311
<FONT COLOR=black>#<FONT COLOR=blue>WrongStringSet.add <U>"gee"</U> WrongStringSet.empty;;
312
<FONT COLOR=maroon>This expression has type string but is here used with type
313
WrongStringSet.element = WrongSet(OrderedString).element
314
</FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></PRE>
315
The problem here is that <TT>SET</TT> specifies the type <TT>element</TT>
316
abstractly, so that the type equality between <TT>element</TT> in the result
317
of the functor and <TT>t</TT> in its argument is forgotten. Consequently,
318
<TT>WrongStringSet.element</TT> is not the same type as <TT>string</TT>, and the
319
operations of <TT>WrongStringSet</TT> cannot be applied to strings.
320
As demonstrated above, it is important that the type <TT>element</TT> in the
321
signature <TT>SET</TT> be declared equal to <TT>Elt.t</TT>; unfortunately, this is
322
impossible above since <TT>SET</TT> is defined in a context where <TT>Elt</TT> does
323
not exist. To overcome this difficulty, Objective Caml provides a
324
<TT>with type</TT> construct over signatures that allows to enrich a signature
325
with extra type equalities:
326
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module AbstractSet =
327
(Set : functor(Elt: ORDERED_TYPE) -> (SET with type element = Elt.t));;
328
<FONT COLOR=maroon>module AbstractSet :
329
functor (Elt : ORDERED_TYPE) ->
334
val add : element -> set -> set
335
val member : element -> set -> bool
337
</FONT></FONT></FONT></PRE>
338
As in the case of simple structures, an alternate syntax is provided
339
for defining functors and restricting their result:
341
module AbstractSet(Elt: ORDERED_TYPE) : (SET with type element = Elt.t) =
344
Abstracting a type component in a functor result is a powerful
345
technique that provides a high degree of type safety, as we now
346
illustrate. Consider an ordering over character strings that is
347
different from the standard ordering implemented in the
348
<TT>OrderedString</TT> structure. For instance, we compare strings without
349
distinguishing upper and lower case.
350
<PRE><FONT COLOR=black>#<FONT COLOR=blue>module NoCaseString =
354
OrderedString.compare (String.lowercase s1) (String.lowercase s2)
356
<FONT COLOR=maroon>module NoCaseString :
357
sig type t = string val compare : string -> string -> comparison end
359
<FONT COLOR=black>#<FONT COLOR=blue>module NoCaseStringSet = AbstractSet(NoCaseString);;
360
<FONT COLOR=maroon>module NoCaseStringSet :
362
type element = NoCaseString.t
363
and set = AbstractSet(NoCaseString).set
365
val add : element -> set -> set
366
val member : element -> set -> bool
369
<FONT COLOR=black>#<FONT COLOR=blue>NoCaseStringSet.add "FOO" <U>AbstractStringSet.empty</U>;;
370
<FONT COLOR=maroon>This expression has type
371
AbstractStringSet.set = AbstractSet(OrderedString).set
372
but is here used with type
373
NoCaseStringSet.set = AbstractSet(NoCaseString).set
374
</FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></FONT></PRE>
375
Notice that the two types <TT>AbstractStringSet.set</TT> and
376
<TT>NoCaseStringSet.set</TT> are not compatible, and values of these
377
two types do not match. This is the correct behavior: even though both
378
set types contain elements of the same type (strings), both are built
379
upon different orderings of that type, and different invariants need
380
to be maintained by the operations (being strictly increasing for the
381
standard ordering and for the case-insensitive ordering). Applying
382
operations from <TT>AbstractStringSet</TT> to values of type
383
<TT>NoCaseStringSet.set</TT> could give incorrect results, or build
384
lists that violate the invariants of <TT>NoCaseStringSet</TT>.<BR>
386
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
387
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
388
<TR><TD><A NAME="htoc17"><B><FONT SIZE=5>2.5</FONT></B></A></TD>
389
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Modules and separate compilation</FONT></B></TD>
390
</TR></TABLE></DIV></TD>
393
All examples of modules so far have been given in the context of the
394
interactive system. However, modules are most useful for large,
395
batch-compiled programs. For these programs, it is a practical
396
necessity to split the source into several files, called compilation
397
units, that can be compiled separately, thus minimizing recompilation
400
In Objective Caml, compilation units are special cases of structures
401
and signatures, and the relationship between the units can be
402
explained easily in terms of the module system. A compilation unit <I>a</I>
405
the implementation file <I>a</I><TT>.ml</TT>, which contains a sequence
406
of definitions, analogous to the inside of a <TT>struct</TT>...<TT>end</TT>
408
<LI>the interface file <I>a</I><TT>.mli</TT>, which contains a sequence of
409
specifications, analogous to the inside of a <TT>sig</TT>...<TT>end</TT>
412
Both files define a structure named <I>A</I> (same name as the base name
413
<I>a</I> of the two files, with the first letter capitalized), as if
414
the following definition was entered at top-level:
416
module <I>A</I>: sig (* contents of file <I>a</I>.mli *) end
417
= struct (* contents of file <I>a</I>.ml *) end;;
419
The files defining the compilation units can be compiled separately
420
using the <TT>ocamlc -c</TT> command (the <TT>-c</TT> option means ``compile only, do
421
not try to link''); this produces compiled interface files (with
422
extension <TT>.cmi</TT>) and compiled object code files (with extension
423
<TT>.cmo</TT>). When all units have been compiled, their <TT>.cmo</TT> files are
424
linked together using the <TT>ocaml</TT> command. For instance, the following
425
commands compile and link a program composed of two compilation units
426
<TT>aux</TT> and <TT>main</TT>:
428
$ ocamlc -c aux.mli # produces aux.cmi
429
$ ocamlc -c aux.ml # produces aux.cmo
430
$ ocamlc -c main.mli # produces main.cmi
431
$ ocamlc -c main.ml # produces main.cmo
432
$ ocamlc -o theprogram aux.cmo main.cmo
433
</PRE>The program behaves exactly as if the following phrases were entered
436
module Aux: sig (* contents of aux.mli *) end
437
= struct (* contents of aux.ml *) end;;
438
module Main: sig (* contents of main.mli *) end
439
= struct (* contents of main.ml *) end;;
441
In particular, <TT>Main</TT> can refer to <TT>Aux</TT>: the definitions and
442
declarations contained in <TT>main.ml</TT> and <TT>main.mli</TT> can refer to
443
definition in <TT>aux.ml</TT>, using the <TT>Aux.</TT><I>ident</I> notation, provided
444
these definitions are exported in <TT>aux.mli</TT>.<BR>
446
The order in which the <TT>.cmo</TT> files are given to <TT>ocaml</TT> during the
447
linking phase determines the order in which the module definitions
448
occur. Hence, in the example above, <TT>Aux</TT> appears first and <TT>Main</TT> can
449
refer to it, but <TT>Aux</TT> cannot refer to <TT>Main</TT>.<BR>
451
Notice that only top-level structures can be mapped to
452
separately-compiled files, but not functors nor module types.
453
However, all module-class objects can appear as components of a
454
structure, so the solution is to put the functor or module type
455
inside a structure, which can then be mapped to a file.
460
<A HREF="manual003.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
461
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
462
<A HREF="manual005.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>