How defining a module signature whose module implementation is parameterized by a functor
functional-programming, functor, module, ocaml
Solution
The natural way to do this is to seal the module at the definition site, not the use site. Then you just need to express the type sharing once:
module M (F : sig type id type data end) :
S with type idtype = F.id and datatype = F.data
= struct ... end
If your functor parameter is more complex then you can also just share an entire module instead of individual types. For example:
module type TYPES = sig type id type data (* ...and more... *) end
module type S =
sig
module Types : TYPES
type component
val create : Types.id -> Types.data -> component
val get_comp_data : component -> Types.data
val get_comp_id : component -> Types.id
end
module M (F : TYPES) : S with module Types = F
= struct ... end
Or you can even parameterise the signature itself, by nesting it into another functor:
module type TYPES = sig type id type data (* ...and more... *) end
module S (F : TYPES) =
struct
module type S =
sig
type component
val create : F.id -> F.data -> component
val get_comp_data : component -> F.data
val get_comp_id : component -> F.id
end
end
module M (F : TYPES) : S(F).S
= struct ... end
Problem
Let's say I have a module `M` parameterized by a module `F`: ``` module M (F : sig type id type data end) = struct type idtype = F.id type datatype = F.data type component = { id : idtype; data : datatype } let create id data = { id; data } let get_comp_data comp = comp.data let get_comp_id comp = comp.id end ``` so I use it like this : ``` module F1 = struct type id = int type data = float end module MF1 = M(F1) let comp = MF1.create 2 5.0 let id = MF1.get_comp_id comp ``` Now, if I want `M` to match signature `S` : ``` module type S = sig type idtype type datatype type component val create : idtype -> datatype -> component val get_comp_data : component -> datatype val get_comp_id : component -> idtype end module F1 = struct type id = int type data = float end module MF1 = (M(F1) : S) let comp = MF1.create 2 5.0 let id = MF1.get_comp_id comp ``` what bothers me here is, in order to define `get_comp_data` and `get_comp_id`, I need to specify `idtype` and `datatype` in module `S`; now just imagine I have other records types in `M` with their own types, I'll have a dozen types to specify in `S`? Is there a simpler way to avoid that?