Have people found ways to functorize whole libraries? By library, I mean a collection of modules written as individual source files. I imagine we would write just mli files without an implementation and have the library exposed as a functor that expects the missing implementation as argument.
This seems doable with a custom build script or something like cppo, but merlin would probably get confused by it. Here’s how it goes:
(* Lib.cppo.mli *)
module type A = sig
#include "A.mli"
end
module type B = sig
#include "B.mli"
end
module type T = sig
type a
type b
module C : sig
#include "C.mli"
end
module D : sig
#include "D.mli"
end
end
module Make (A : A) (B : B) : T with type a = A.t
and type b = B.t
and
(* Lib.cppo.ml *)
module type A = sig
#include "A.mli"
end
module type B = sig
#include "B.mli"
end
module type T = sig
type a
type b
module C : sig
#include "C.mli"
end
module D : sig
#include "D.mli"
end
end
module Make (A : A) (B : B) = struct
type a = A.t
type b = B.t
module C = struct
#include "C.ml"
end
module D = struct
#include "D.ml"
end
end
and A.mli
and B.mli
each contain just this:
type t
The other ml and mli files are empty in this example.
This can be compiled as follows:
$ cppo Lib.cppo.mli > Lib.mli && cppo Lib.cppo.ml > Lib.ml && ocamlc -a -o Lib.cma Lib.mli Lib.ml
giving us the following compact signature for the library’s root module Lib
:
$ cmitomli Lib.cmi
module type A = sig type t end
module type B = sig type t end
module type T = sig type a type b module C : sig end module D : sig end end
module Make :
functor (A : A) (B : B) ->
sig type a = A.t type b = B.t module C : sig end module D : sig end end
I’m not quite sure about the practicality of all this. It would be very nice to have one file per module or per module interface rather than cramming everything into one giant file, but perhaps that’s the best approach for now. Has anyone tried other approaches?