Place all derived functions into a functor?
Hello!
I'm working on a Ppxlib deriving extension which transforms types into functions (specifically deriving serialization decoders).
I would like to somehow make all of the generated functions encapsulated into a functor that I can then instantiate with a module.
E.g.
(*In file `file.ml` *)
type a = int [@deriving my_ext]
(* makes `a_fun`*)
type b = int * string [@deriving my_ext]
(* makes `b_fun`*)
(* I somehow want to have the above `a_fun` and `b_fun` *) placed into a functor like `File_my_ext` *)
let My_gen_mod = File_my_ext(<MODULE>)
One possible solution is to make it so that
type a = int [@deriving my_ext]
type b = int * string [@deriving my_ext]
generates code like
module File_my_ext (Input : Sig) = struct end
type a = int [@deriving my_ext]
module File_my_ext (Input : Sig) = struct
include File_my_ext(Input)
let a_fun = <FUN>
end
type b = int * string [@deriving my_ext]
module File_my_ext (Input : Sig) = struct
include File_my_ext(Input)
let b_fun = <FUN>
end
I believe this would work, though it feels quite clunky as I am having to create all of these intermediary functors and instantiate them along the way. Is there a more natural way to do this?
If its relevant, that top level of my extension consists of
Deriving.add name ~str_type_decl |> Deriving.ignore
for some implementation of str_type_decl
Thanks!!
Unfortunately what you suggest is not strictly possible. There are a few things you could do to make it work:
- You can deal with groups of type declarations, if I reuse your above example, you can group both your type declarations together so that the deriver is applied to all of them at once:
type a = int
and b = int * string
[@@deriving my_ext]
- You can also group your type declarations in a module and write a rule to generate your functor based on the types declared in said module. The deriving API currently only supports module types but we could consider extending it if needed. E.g. atm you could do:
module type S = sig
type a = int
type b = int * string
end
[@@deriving my_ext]
Given you are trying to generate a functor, doing so from a module type seems like a more logical approach!
If you give me a bit more context on what deriver you are working on and how you plan to use it I may be able to provide more helpful hints!
Ah thanks a ton for the help!
Upon further thought, I am thinking it may make the most sense to just have the user of the extension encapsulate the generated functions in a module by hand, i.e.:
module S (D : MOD_TYPE) = struct
open D
type a = int [@@deriving my_ext]
type b = int * string [@@deriving my_ext]
end
let module Instantiated = S(Some_D)
I don't love having to make the user encapsulate their types into a functor, but I think it will work easiest for my current implementation.
I actually changed my mind and decided I like approach 2 you suggested above better! But I'm still a bit unsure how to get it quite right.
To give you a little bit more context, I am working on a deriving library for decoders. It's a decoding library that allows you to use decoder combinators to write decoders for a multiple formats (e.g. JSON, XML, etc.).
Here is what I would like to happen:
module X = struct
type t = int * string
end [@@deriving decoders]
--via-ppx-->
module X = struct
type t = int * string
module Encode (D : Decoders.Decode.S) = struct
let t_decode = <SOME IMPLE USING D>
end
end
It does already work to do:
module X = struct
module D = <MAKE D AVAILABLE>
type t = int * string [@@deriving decoders]
end
--via-ppx-->
module X = struct
module D = <MAKE D AVAILABLE>
type t = int * string
let t_decoder = <IMPLE USING D>
end
I tried the approach with using signatures, but the problem is that the implementation needs to be dumped into the implementation module, rather than the signature module.
Any guidance would be much appreciated. Thanks!