After being lazy for some years, I decided to get a grasp of first class modules. So far so good but I’m currently stuck within my experiments mainly in relation to the way one can add typing constraints to such module values.
Writing a function apply
of type ('a -> 'b) -> 'a -> 'b
is done trivially as let apply f arg = f arg
.
Suppose that it is not one function but a set of functions I want to give to apply
. I can define a module and use first class modules.
module type MTYPE = sig type input type output val f: input -> output end
let apply1 m arg =
let module M = (val m: MTYPE) in
M.f arg
This code raise an error: The type constructor M.input would escape its scope. One possible solution is to use existential types:
let apply2 (type a b) m arg =
let module M = (val m: MTYPE with type input = a and type output = b) in
M.f arg
This code compiles and works great but it forces me to define the types input
and output
in the implementations though the typer computed them…
Q1: is there a way to do this without requiring the developer to define input
and output
? I would have liked to say:
let apply3 (type a b) m arg =
let module M = (val m: sig val f: a -> b end) in
M.f arg
but the compiler raises an error: invalid package type: only module type identifier and ‘with type’ constraints are supported.
Sticking with apply2
, I now want the module argument to be a functor. For example, supposing:
module type PTYPE = sig type ('a,'b) ty end
module type MTYPE' = functor (P:PTYPE) -> MTYPE
module I: PTYPE =
struct
type ('a,'b) ty = ('a * 'b) list
end
I would like to write:
let apply4 (type a b) m arg =
let module M = (val m: functor (P:PTYPE) -> sig val f: a -> b end) (I) in
M.f arg
which is still not possible so I tried:
let apply5 (type a b) m arg =
let module M = (val m: MTYPE' with type input = a and type output = b) (I) in
M.f arg
That does not work: Error: This module type is not a signature.
Q2: is there a way to link the input and output type of the functor to my existential types?
Thank you in advance