Interface with multiple implementations in OCaml

You must use modules and signatures. A .ml file implicitly define a module, and a .mli its signature. With explicit modules and signature, you can apply a signature to several different modules.

See this chapter of the online book "Developing Applications with OCaml".


If you're going to have multiple implementations for the same signature, define your signature inside a compilation unit, rather than as a compilation unit, and (if needed) similarly for the modules. There's an example of that in the standard library: the OrderedType signature, that describes modules with a type and a comparison function on that type:

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

This signature is defined in both set.mli and map.mli (you can refer to it as either Set.OrderedType or Map.OrderedType, or even write it out yourself: signatures are structural). There are several compilation units in the standard library that have this signature (String, Nativeint, etc.). You can also define your own module, and you don't need to do anything special when defining the module: as long as it has a type called t and a value called compare of type t -> t -> int, the module has that signature. There's a slightly elaborate example of that in the standard library: the Set.Make functor builds a module which has the signature OrderedType, so you can build sets of sets that way.

(* All four modules passed as arguments to Set.Make have the signature Set.OrderedType *)
module IntSet = Set.Make(module type t = int val compare = Pervasives.compare end)
module StringSet = Set.Make(String)
module StringSetSet = Set.Make(StringSet)
module IntSetSet = Set.Make(IntSet)