module <name> =
struct
..
end;;
module type <name> =
struct (* should have been sig *)
..
end;;
What are functors and why do we need them? A functor is a module that is parametrized by another module, just like a function is a value which is parametrized by other values, the arguments. It allows one to parametrize a type by a value, which is not possible directly in OCaml without functors.
ocaml modules allow to package together data structures definitions and functions operating on them. This allow to reduce code size and name confusion, as any identifier can appear in different modules, with different meanings, without any interference.
A signature specifies which components of a structure are accessible from the outside, and with which type. It can be used to hide some components of a structure (e.g. local function definitions) or export some components with a restricted type.
The first declares a module and the second declares a module type (aka a signature). A module type contains type
and val
declarations, whereas a module can contain definitions (e.g., let
bindings). You can use a signature to restrict the type of a module, much as you might for a function. For example,
module type T = sig
val f : int -> int
end
module M : T = struct
let f x = x + 1
let g x = 2 * x
end
Now, we have
# M.f 0 ;;
- : int = 1
# M.g 0 ;;
Error: Unbound value M.g
M.g
is unbound because it's hidden by the signature T
.
Another common way to use module types is as arguments to and return values of functors. For example, the Map.Make
functor in the standard library takes a module with signature Map.OrderedType
and creates a module with signature Map.S
P.S. Note that there's a mistake in the question. A module type is declared using
module type <name> = sig
...
end
A structure (written struct … end
) is a bunch of definitions. Any object in the language can be defined in a module: core values (let x = 2 + 2
), types (type t = int
), modules (module Empty = struct end
), signatures (module type EMPTY = sig end
), etc. Modules are a generalization of structures: a structure is a module, and so is a functor (think of it as a function that takes a module as argument and returns a new module). Modules are like core values, but live one level above: a module can contain anything, whereas a core value can only contain other core values¹.
A signature (written sig … end
) is a bunch of specifications (some languages use the term declaration). Any object in the language can be specified in a module: core values (val x : int
), types (type t = int
), modules (module Empty : sig end
), signatures (module type EMPTY = sig end
), etc. Module types generalize signatures: a module type specifies a module, and a module type that happens to specify a structure is called a signature. Module types are to modules what ordinary types are to core values.
Compilation units (.ml
files) are structures. Interfaces (.mli
files) are signatures.
So module Foo = struct … end
defines a module called Foo
, which happens to be a structure. This is analogous to let foo = (1, "a")
which defines a value called foo
which happens to be a pair. And module type FOO = sig … end
(note: sig
, not struct
) defines a module type called FOO
, which happens to be a signature. This is analogous to type foo = int * string
which defines a type called foo
which happens to be a product type.
¹ This is in fact no longer true since OCaml 3.12 introduced first-class modules, but it's close enough for an introductory presentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With