'How can a module defined in a .ml file reference itself
I am trying to define a Point
module that defines a type to represent 2d points.
I would also like to include a submodule Point.Set
so that Point.Set.t
is
a type meaning 'a set of Points'. That seems logical and convenient, but I am not able to figure out how to make the 'circular' reference that this involves.
I tried this:
file: point.ml (implicitly defines a 'Point' module)
type t = {x: int; y:int}
let compare {x=x1;y=y1} {x=x2;y=y2} = ...implementation omitted for brevity...
module Set = Stdlib.Set.Make(Point)
(* ^^^^^ Internal path Mylib__Point is dangling *)
When I dune build
the Mylib
project/library this is in. I get an error:
Internal path Mylib__Point is dangling.
The compiled interface for module Mylib__Point was not found.
I am not entirely sure what the error really means, but I gather it probably has something to do with the fact that we are trying to reference the Point
module from within itself. And maybe that is not allowed?
I can work around this by instead defining a separate 'pointSet.ml' file and in there have include Set.Make(Point)
. Now I have a module called PointSet
. That is okay, but I still would find it a bit more 'aesthetically pleasing' if Point.Set
could be a submodule of Point
instead. Is there a way to make this work?
Solution 1:[1]
If you don't mind a little bit of boilerplate, I think this solution may suit you:
point.ml
module Point = struct
type t = { x : int; y : int }
let compare { x = x1; y = _y1 } { x = x2; y = _y2 } = x1 - x2
end
module Set : Set.S with type elt = Point.t = Set.Make (Point)
include Point
You'll have access to Point.Set
and since point.ml
includes the module Point
at the end of the file, you won't have to do Point.Point.compare ...
in other files.
[EDIT]
I previously made the modules mutually recursive but in this case it's useless. If you need them to be mutually recursive you'll have to explicit their signatures:
point.ml
module rec Point : sig
type t
val compare : t -> t -> int
end = struct
type t = { x : int; y : int }
let compare { x = x1; y = _y1 } { x = x2; y = _y2 } = x1 - x2
end
and Set : (Stdlib.Set.S with type elt = Point.t) = Stdlib.Set.Make (Point)
include Point
Solution 2:[2]
As far as I know a module doesn't have a name for itself. You can make a module (a struct) just for the purpose of supplying it to the functor Set.Make:
type t = { x : int; y : int }
let compare a b = compare a b
module Set =
Set.Make(struct type nonrec t = t let compare = compare end)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Jeffrey Scofield |