I am experimenting with the module language of OCaml (3.12.1), defining functors and signatures for modules and so on, mostly following the examples from Chapter 2 of the OC
The :
construct is different in the core language and in the module language. In the core language, it is an annotation construct. For example, ((3, x) : 'a * 'a list)
constrains the expression to have some type that is an instance of 'a * 'a list
; since the first element of the pair is an integer, let (a, b) = ((3, x) : 'a * 'a list) in a + 1
is well-typed. The :
construct on modules does not mean this.
The construct M : S
seals the module M
to the signature S
. This is an opaque seal: only the information given in the signature S
remains available when typing uses of M : S
. When you write module IntType : SOMETYPE = struct type t end
, this is an alternate syntax for
module IntType = (struct type t end : SOMETYPE)
Since the type field t
in SOMETYPE
is left unspecified, IntType
has an abstract type field t
: the type IntType
is a new type, generated by this definition.
By the way, you probably meant module IntType = (struct type t = int end : SOMETYPE)
; but either way, IntType.t
is an abstract type.
If you want to specify that a module has a certain signature while leaving some types exposed, you need to add an explicit equality for these types. There's no construct to add all inferable equalities, because applying a signature to a module is usually meant for information hiding. In the interest of simplicity, the language only provides this one generative sealing construct. If you want to use the defined signature SOMETYPE
and retain the transparency of the type t
, add a constraint to the signature:
module IntType = (struct type t = int end : SOMETYPE with type t = int)