I have a module signatures like this:
module type Base_X = sig
type t
end
module type Base_Y = sig
type t
end
module type A_sig = sig
module Some_X : Base_X
module Some_Y : Base_Y
module Z : sig
val f : Some_X.t -> Some_Y.t
end
end
and two types x
and y
.
Modules that implement A_sig
will define Some_X
and Some_Y
as extending Base_X
and Base_Y
in a way that allows instances of x
and y
to be converted to Some_X.t
and from Some_Y.t
. For instance, one implementation of Some_X
might have type
module type X1_sig = sig
type t
val x_to_string : x -> string
val string_to_t : string -> t
end
For each possible module type like X1_sig
there will be a functor X1_func
(or function using first-class modules) that takes Some_X1 : X1_sig
to (a module containing) a function x -> Some_X1.t
, and likewise there will be functors to create functions Some_Y.t -> y
.
I would like to define a functor Make
that takes a module A : A_sig
and appropriate functors X_func
and Y_func
, and produces a function f : x -> y
by chaining X_func
, A.Z.f
and Y_func
. It seems like this isn’t possible to do completely generally, and multiple Make
functors are needed for different values of X_func
and Y_func
. But is there a way to do it more generally than by defining specific versions of Make
for each possible pair of X_sig/X_func
and Y_sig/Y_func
? I would be happy with an approach that handles each X_sig
and Y_sig
separately, but I can’t work out how to do that (defining a functor/function with type x -> Some_X1.t
causes the type constructor Some_X1.t
to escape its scope).