Advanced Module System

Removes a type from a signature by replacing it:

30.1 Destructive substitution :=

Removes a type from a signature by replacing it:

module type S = sig type t val x : t end
module type S_int = S with type t := int   (* sig val x : int end *)
module type S2 = sig include S with type t := string val y : int end

30.2 module type of

module type LIST = module type of List
module MyList : sig
  include module type of struct include List end
  val sum : int list -> int
end = struct
  include List
  let sum = fold_left ( + ) 0
end

30.3 Recursive modules

Classic use: a set of trees whose nodes contain sets of trees:

module rec Even : sig val check : int -> bool end = struct
  let check n = n = 0 || Odd.check (n - 1)
end
and Odd : sig val check : int -> bool end = struct
  let check n = n <> 0 && Even.check (n - 1)
end
module rec Tree : sig type t = Node of string * TreeSet.t val compare : t -> t -> int end = struct
  type t = Node of string * TreeSet.t
  let compare = compare
end
and TreeSet : Set.S with type elt = Tree.t = Set.Make (Tree)

30.4 Generative vs applicative functors

module F (X : sig end) = struct type t = int end   (* applicative: F(A).t = F(A).t *)
module G () = struct type t end                     (* generative: each G () gives a fresh type *)
module Id1 = G ()
module Id2 = G ()
(* Id1.t and Id2.t are distinct types: useful for unique-token / capability patterns *)

30.5 Higher-order functors

module Apply (F : functor (X : ORDERED) -> sig type t end) (X : ORDERED) = F (X)

30.6 Module aliases & -no-alias-deps

module L = List costs nothing; dune uses aliases to implement library wrapping.

30.7 Signature design patterns

S / Make / Intf pattern: module type S = sig ... end plus module Make (X : Arg) : S with type t = X.t.

_intf.ml files (Jane Street style) for sharing signatures between .ml and .mli.

Comparable / Hashable mixins: functors adding compare, Map, Set to any type.

module type COMPARABLE = sig
  type t
  val compare : t -> t -> int
end

module Make_comparable (X : COMPARABLE) = struct
  include X
  let equal a b = compare a b = 0
  let ( < ) a b = compare a b < 0
  let max a b = if compare a b >= 0 then a else b
  module Map = Map.Make (X)
  module Set = Set.Make (X)
end

30.8 Packing modules with type constraints

module type ID = sig type t val of_string : string -> t end
let m = (module struct type t = string let of_string s = s end : ID with type t = string)

30.9 Modular implicits / type classes

OCaml has no type classes; emulate with explicit dictionary passing via first-class modules:

module type SHOW = sig type t val show : t -> string end
let show_list (type a) (module S : SHOW with type t = a) (l : a list) =
  "[" ^ String.concat "; " (List.map S.show l) ^ "]"
let _ = show_list (module struct type t = int let show = string_of_int end) [1;2]