I just want to have a simple function that is generic over Hashtbls so I wrote this:
let iter_htbl (type a) (module H : Hashtbl.S with type key = a) htbl =
H.iter (fun _key _v -> ()) htbl
Which gives me the following error:
53 | H.iter (fun _key _v -> ()) htbl
^^^^
Error: This expression has type 'a but an expression was expected of type
'b H.t
The type constructor H.t would escape its scope
And if I write:
let iter_htbl (type a b) (module H : Hashtbl.S with type key = a) (htbl : b H.t)
=
H.iter (fun _key _v -> ()) htbl
New error (but almost the same):
52 | let iter_htbl (type a b) (module H : Hashtbl.S with type key = a) (htbl : b H.t)
^^^^^^^^^^^^^^
Error: This pattern matches values of type b H.t
but a pattern was expected which matches values of type 'a
The type constructor H.t would escape its scope
Is there a solution for what I'm trying to achieve?
Of course, in my simple case I could write
let iter_htbl iter htbl =
iter (fun _key _v -> ()) htbl
But if I want to use multiple functions from H
this is not a useful solution.
That won't work. Unfortunately, OCaml's type system cannot express this directly. That would require higher-kinded polymorphism, which the ML core language does not have:
let iter_htbl (type key) (type 'a htbl) (type a) (module H : Hashtbl.S with type key = key with type 'a t = 'a htbl) (htbl : a htbl) = ...
The (type 'a htbl)
there is a syntax error – for a reason, because that kind of polymorphism over a parameterised type cannot easily be reconciled with type inference (at least not without certain restrictions), as it would require higher-order unification in the general case, which is undecidable.
The only way to abstract over a parameterised type like H.t in ML is by lifting to the module level and writing a functor:
module IterHtbl (H : Hashtbl.S) (T : sig type a val htbl : a H.t end) =
struct
let it = H.iter (fun _ _ -> ()) T.htbl
end
That works, because modules are more explicitly typed.