First-Class Modules

Modules can be packed into ordinary values and unpacked at runtime.

Choosing an implementation at runtime:

Using first-class modules with locally abstract types:

module type SHAPE = sig
  val name : string
  val area : unit -> float
end

let make_circle r = (module struct
  let name = "circle"
  let area () = Float.pi *. r *. r
end : SHAPE)

let make_square s = (module struct
  let name = "square"
  let area () = s *. s
end : SHAPE)

let shapes = [ make_circle 1.0; make_square 2.0 ]

let () =
  List.iter (fun (module S : SHAPE) ->
    Printf.printf "%s: %.2f\n" S.name (S.area ())) shapes
let get_backend = function
  | "memory" -> (module Memory_store : STORE)
  | _ -> (module File_store : STORE)

let module B = (val get_backend "memory" : STORE) in
B.save "k" "v"
let sort_unique (type a) (module O : Set.OrderedType with type t = a) (xs : a list) =
  let module S = Set.Make (O) in
  S.elements (S.of_list xs)

sort_unique (module Int) [3;1;3;2]    (* [1;2;3] *)