Create module at runtime?

I think first class modules might be what I want, but I’m not sure. Here’s what I’m trying to do:

Let’s say I have some items which I want to add to a container but at runtime I want to decide whether items in the container should be unique. If true I want to use a Set if false I want to use a List.

In other languages this would be simple to do at runtime by creating different instances of an interface, what is the idiomatic way of doing this kind of think in OCaml?

Here’s a silly example of the kind of thing I’d like to be able to do:

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

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