Functor, Application and magick!
While I try to make an SMTP server in OCaml as an unikernel, I tried to deal
with Set.Make
. Imagine a situation where you define your type elt = string
into a module A
and you want to apply Set.Make
inside the given module.
Interface
Then, you would like to write a proper interface which describe result of your functor. It should be easy than:
type elt = string
include Set.S with type elt = elt
But in my example, ~Set.S~ wants to (re)define elt
. You probably miss the
destructive substitution of the type elt
.
type elt = string
include Set.S with type elt := elt
Implementation
The implementation will be more trickier. Indeed, we probably want to do something like this:
include Set.Make(struct type t = string let compare = String.compare end)
And, fortunately for you, this snippet should work. However, it starts to be
pretty incomprehensible when type elt
is one of your type (string
or
String.t
exists outside the scope of your module). We can take this example:
include Set.Make(struct
type t = { v : string }
let compare { v= a; } { v= b; } = String.compare a b
end)
Into the interface, by side the redefinition of the type elt
, nothing should
change. However, the compilation fails with:
$ ocamlc -c a.ml
Error: The implementation a.ml does not match the interface a.cmi:
Type declarations do not match:
type elt
is not included in
type elt = { v : string; }
Indeed, we should have a definition of elt
outside the struct ... end
:
type elt = { v : string }
include Set.Make(struct
type t = elt
let compare { v= a; } { v= b; } = String.compare a b
end)
However, now, OCaml complains about a multiple definition of the type elt
.
May be we can play more with the destructive substitution?
type elt = { v : string }
include
(Set.Make(struct
type t = elt
let compare { v= a; } { v= b; } = String.compare a b
end)
: Set.S with type elt := elt)
And it's work!
Just a tip
So I leave this trick here to help some people.