.ml 文件中定义的模块如何引用自身

How can a module defined in a .ml file reference itself

我正在尝试定义一个 Point 模块,它定义了一个表示 2d 点的类型。

我还想包含一个子模块 Point.Set 以便 Point.Set.t 一个类型,意思是 'a set of Points'。这似乎合乎逻辑且方便,但我无法弄清楚如何制作这涉及的 'circular' 参考。

我试过这个:

文件:point.ml(隐式定义了一个'Point'模块)

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 *)

当我 dune build Mylib project/library 时,我得到一个错误:

Internal path Mylib__Point is dangling.
  The compiled interface for module Mylib__Point was not found.

我不完全确定错误的真正含义,但我认为它可能与我们试图引用 Point模块本身。也许这是不允许的?

我可以通过定义一个单独的 'pointSet.ml' 文件来解决这个问题,其中有 include Set.Make(Point)。现在我有一个名为 PointSet 的模块。没关系,但如果 Point.Set 可以是 Point 的子模块,我仍然会发现它 'aesthetically pleasing' 多一点。有没有办法让这个工作?

据我所知,模块本身没有名称。你可以制作一个模块(一个结构)只是为了将它提供给仿函数 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)

如果您不介意一些样板文件,我认为这个解决方案可能适合您:

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

您将可以访问 Point.Set,并且由于 point.ml 在文件末尾包含模块 Point,因此您不必执行 Point.Point.compare ...在其他文件中。


[编辑]

我之前让模块相互递归,但在这种情况下它没用。如果你需要它们相互递归,你必须明确它们的签名:

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