Create module at runtime?

The most direct translation of what you propose is to have a common signature for both modules:

module type S = sig
  type elt
  type t
  val empty : t
  val add: elt -> t -> t
  val count: t -> int
end

and two ways to produce this signature, from a list and from a set:

module S_list (T : sig type t end): S = struct
  type elt = T.t
  type t = elt list
  let empty = []
  let add x l = x :: l
  let count = List.length
end

module S_set (O : Set.OrderedType) : S = struct
  module Set = Set.Make (O)
  type elt = O.t
  type t = Set.t
  let empty = Set.empty
  let add = Set.add
  let count = Set.cardinal
end

Then you can just use switch between the two implementations depending on the value of unique:

module S_intlist = S_list (struct type t = int end)
module S_intset = S_set (struct type t = int let compare = compare end)

let count_items (unique : bool) (items : int list) =
  let (module Thing) = if unique then (module S_intset : S) else (module S_intlist : S) in
  let container = Thing.empty in
  let added = List.fold items ~init:container ~f:(fun c v -> Thing.add c v) in
  Thing.count added

Cheers,
Nicolás

2 Likes