After getting used to plan to instantiate functors outside other functors, I get along well in practice now. The module type of syntax (that I recently discovered and shared in my post above) helps too.
For my convenience, however, I ended up with something like this (work still in progress):
module Make
(Num : Number.S)
(Vec : module type of Vector.Make (Num))
(VectorSet : module type of Set.Make (Vec))
(* ... *) : sig
(* ... *)
end
module MakeWithDeps (Num : Number.S) : sig
module Num : module type of Num
module Vec : module type of Vector.Make (Num)
module VectorSet : module type of Set.Make (Vec)
(* ... *)
module M : module type of Make (Num) (Vec) (VectorSet) (* ... *)
end
Edit: Actually I need to use this slightly more complex syntax to ensure that abstract types remain compatible:
module MakeWithDeps (Num : Number.S) : sig
module Num : module type of struct
include Num
end
module Vec : module type of struct
include Vector.Make (Num)
end
module VectorSet : module type of struct
include Set.Make (Vec)
end
(* ... *)
module M : module type of Make (Num) (Vec) (VectorSet) (* ... *)
See the first example code in the OCaml manual on Recovering the type of a module in that matter.
End of edit.
This allows me to create all required modules conveniently (using MakeWithDeps, that just requires the number module), but still allows a user to provide their own vectors, vector sets, etc. to Make.
Itâs something that works, but I still feel like it is suboptimal regarding the level of abstraction that I would like to express, ideally.
What feels odd is: I abstract over concrete modules (with module type of), to then later fit in concrete instantiations again:
module MakeWithDeps (Num : Number.S) = struct
module Num = Num
module Vec = Vector.Make (Num)
module VectorSet = Set.Make (Vec)
(* ... *)
module M = Make (Num) (Vec) (VectorSet) (*...*)
end
Is there a (tracking) issue that I could follow? Or a keyword I could search for on the issue tracker, so I get updated on any changes? Or any roadmap? Or is this just a rough not-written-down plan at this stage?
I found âSub-module identities inside an applicative functor are actually generative, leading to invalid signatures ¡ Issue #13173 ¡ ocaml/ocaml ¡ GitHubâ, but that seems to be be different issue.
Do other people have struggles with nested functors or is there some reading material on the issue? I attempted some AI query
, and was referred to âbuilder modulesâ, like MakeWithDeps above, but trying to find concrete examples wasnât fruitful. So is this really something used in practice? (See also @n4323âs post above, asking if there is some general guide to functors which covers these more complex cases.)