I’ve been playing around more with first-class modules and came across this particular use case (briefly mentioned in Including and re-exporting types as abstract)
If you have a module signature with a non-abstract type, i.e.
module type S = sig
type 'a t
type existential = E : 'a t -> existential
end
and you want to write a function that takes a module S
and an S.existential
, there are a couple of ways that I thought about achieving this:
let f (module M : S) (v : M.existential) = ()
This seems like it should work, but doesn’t:
Error: This pattern matches values of type M.existential
but a pattern was expected which matches values of type 'a
The type constructor M.existential would escape its scope
And it’s kind of easy to see why: how would one write a type signature for this function? I don’t think it’s doable.
Another thought I had was to use locally abstract types:
let (type e) (module M : S with type existential = e) (v : e) = ()
This also doesn’t work, since M.existential
is not abstract, and so we get:
Error: In this `with' constraint, the new definition of existential
does not match its original definition in the constrained signature:
Type declarations do not match:
type existential
is not included in
type existential = E : 'a t -> existential
Their kinds differ.
Is there any way to write the function like this without packing the arguments into another module?