@Drup suggested that the following is possibly inferior or more complex than using objects:
module type S = sig
type t
val do_thing : t -> t -> t
val to_string : t -> string
val other_function : ....
end
type 'a state = ('a * (module S with type t = 'a))
I see his point but as an alternative, I was thinking of doing something like this:
(* A basic, typical module definition. *)
module type S = sig
type t
val get : t -> unit -> bool
end
(* An implementation of [S] which simply returns its associated value. *)
module Id : S with type t = bool = struct
type t = bool
let get t () = t
end
(* In spirit of [S], but with [type t] stripped out of the signature. *)
module type S' = sig val get : unit -> bool end
(* Functor to convert an [S] to [S'], given a factory function for producing values of [type t]. *)
module Make(T : sig include S val create : unit -> t end) : S' =
struct
let t = T.create ()
let get = T.get t
end
(** Example instantiations of [S'] from [S]. *)
module Always_true = Make(struct include Id let create () = true end)
module Always_false = Make(struct include Id let create () = false end)
(* Example of a function aggregating over all the module instances. *)
let for_all l = List.for_all (fun (module T:S') -> T.get ()) l
(** Should return [false]. *)
let result = for_all [(module Always_true);(module Always_false)]