6.11 Module expressions (module implementations)
Module expressions are the module-level equivalent of value
expressions: they evaluate to modules, thus providing implementations
for the specifications expressed in module types.
module-expr |
::= |
module-path |
|
∣ |
struct { definition [;;] } end |
|
∣ |
functor ( module-name : module-type ) -> module-expr |
|
∣ |
module-expr ( module-expr ) |
|
∣ |
( module-expr ) |
|
∣ |
( module-expr : module-type ) |
definition |
::= |
let [rec] let-binding { and let-binding } |
|
∣ |
external value-name : typexpr = external-declaration |
|
∣ |
type-definition |
|
∣ |
exception-definition |
|
∣ |
class-definition |
|
∣ |
classtype-definition |
|
∣ |
module module-name { ( module-name : module-type ) }
[ : module-type ] = module-expr |
|
∣ |
module type modtype-name = module-type |
|
∣ |
open module-path |
|
∣ |
include module-expr |
6.11.1 Simple module expressions
The expression module-path evaluates to the module bound to the name
module-path.
The expression ( module-expr ) evaluates to the same module as
module-expr.
The expression ( module-expr : module-type ) checks that the
type of module-expr is a subtype of module-type, that is, that all
components specified in module-type are implemented in
module-expr, and their implementation meets the requirements given
in module-type. In other terms, it checks that the implementation
module-expr meets the type specification module-type. The whole
expression evaluates to the same module as module-expr, except that
all components not specified in module-type are hidden and can no
longer be accessed.
Structures struct … end are collections of definitions for
value names, type names, exceptions, module names and module type
names. The definitions are evaluated in the order in which they appear
in the structure. The scope of the bindings performed by the
definitions extend to the end of the structure. As a consequence, a
definition may refer to names bound by earlier definitions in the same
structure.
For compatibility with toplevel phrases (chapter 9)
and with Caml Light, an optional ;; is allowed after each
definition in a structure. The ;; has no semantic meaning. Also for
compatibility, ;; expr is allowed as a component of a structure,
meaning let _ = expr, i.e. evaluate expr for its side-effects.
Value definitions
A value definition let [rec] let-binding { and let-binding }
bind value names in the same way as a let … in … expression
(see section 6.7.1). The value names appearing in the
left-hand sides of the bindings are bound to the corresponding values
in the right-hand sides.
A value definition external value-name : typexpr = external-declaration
implements value-name as the external function specified in
external-declaration (see chapter 18).
Type definitions
A definition of one or several type components is written
type typedef { and typedef } and consists of a sequence
of mutually recursive definitions of type names.
Exception definitions
Exceptions are defined with the syntax exception constr-decl
or exception constr-name = constr.
Class definitions
A definition of one or several classes is written class
class-binding { and class-binding } and consists of a sequence of
mutually recursive definitions of class names. Class definitions are
described more precisely in section 6.9.3.
Class type definitions
A definition of one or several classes is written
class type classtype-def { and classtype-def } and consists of
a sequence of mutually recursive definitions of class type names.
Class type definitions are described more precisely in
section 6.9.5.
Module definitions
The basic form for defining a module component is
module module-name = module-expr, which evaluates module-expr and binds
the result to the name module-name.
One can write
module module-name : module-type = module-expr
instead of
module module-name = ( module-expr : module-type ).
Another derived form is
module module-name ( name1 : module-type1 ) …
( namen : module-typen ) = module-expr
which is equivalent to
module module-name =
functor ( name1 : module-type1 ) -> …
-> module-expr
Module type definitions
A definition for a module type is written
module type modtype-name = module-type.
It binds the name modtype-name to the module type denoted by the
expression module-type.
Opening a module path
The expression open module-path in a structure does not define any
components nor perform any bindings. It simply affects the parsing of
the following items of the structure, allowing components of the
module denoted by module-path to be referred to by their simple names
name instead of path accesses module-path . name. The scope of
the open stops at the end of the structure expression.
Including the components of another structure
The expression include module-expr in a structure re-exports in
the current structure all definitions of the structure denoted by
module-expr. For instance, if the identifier S is bound to the
module
struct type t = int let x = 2 end
the module expression
struct include S let y = (x + 1 : t) end
is equivalent to the module expression
struct type t = int let x = 2 let y = (x + 1 : t) end
The difference between open and include is that open
simply provides short names for the components of the opened
structure, without defining any components of the current structure,
while include also adds definitions for the components of the
included structure.
Functor definition
The expression functor ( module-name : module-type ) ->
module-expr evaluates to a functor that takes as argument modules of
the type module-type1, binds module-name to these modules,
evaluates module-expr in the extended environment, and returns the
resulting modules as results. No restrictions are placed on the type of the
functor argument; in particular, a functor may take another functor as
argument (“higher-order” functor).
Functor application
The expression module-expr1 ( module-expr2 ) evaluates
module-expr1 to a functor and module-expr2 to a module, and
applies the former to the latter. The type of module-expr2 must
match the type expected for the arguments of the functor module-expr1.