I like parametricity, and prefer as much as possible to use parametric data-types than functors. Even though this may have a cost at runtime. Following this paradigm, assume I want to write a program that requires to use a set
data-structure but I want to be parametric over the type of my elements. Using the standard library of OCaml, I could use a functor:
module Make (C : sig
type param
module Set : Set.S with type elt = param
end) =
struct
type t = {foo : int; bar : C.Set.t}
(* ... *)
end
but as I said, I would prefer to avoid those for various personal reasons.
This is actually doable by doing so:
type 'param set =
| E : {
md : (module Set.S with type elt = 'param and type t = 'a);
set : 'a;
}
-> 'param set
type 'param t = {foo : int; bar : 'param set}
I can write some wrappers for using functions declared by the signature Set.S
my new datatype, but it works.
I will pay some runtime cost by boxing/unboxing the module and the corresponding set but that’s fine.
Next problem: Can I do the same thing for a Map
? Well, it is a bit more involved. Sure, I could use a hashtbl
instead, but I would like my program to be functional.
The solution I came up with is the following:
module type MAP = sig
type key
type value
include Map.S with type key := key
type map
val inj : value t -> map
val proj : map -> value t
end
type ('key, 'value) t =
| E : {
foo :
(module MAP
with type key = 'key
and type value = 'value
and type map = 'c);
bar : 'c;
}
-> ('key, 'value) t
(* An example to implement such MAP signature *)
module Map : MAP with type key = int and type value = int = struct
type value = int
include Map.Make (Int)
type map = value t
let inj (x : value t) : map = x [@@inline]
let proj (x : map) : value t = x [@@inline]
end
This time, I need to use inj
and proj
functions which were not necessary for the case of set
. The reason is that I cannot write in the MAP
signature the equality:
type map = value t
Otherwise the declaration of ('key,'value) t
is invalid:
Error: In this 'with' constraint, the new definition of map
does not match its original definition in the constrained signature:
Type declarations do not match:
type map
is not included in
type map = value t
However, I believe that because the type variable 'c
is hidden via a GADT, logically it could behave as an existential. Consequently, I wonder whether it would be a valid extension of the type system of OCaml to accept my signature MAP
where the definition of type map
is exposed with the datatype ('key,'value) t
given above? If not, I would be curious to understand why?
Out of curiosity, is there any “better” way (easier to use, better performances, …) to achieve a similar result?