为什么要求OCaml中的相互递归模块中的签名?

Ash*_*she 9 ocaml module mutual-recursion

在OCaml中使用相互递归的模块定义时,即使在.ml文件中也必须提供签名.这是一个烦恼,我也希望从中公开给定的接口.mli,因为我最终重复签名两次.:(!

module rec Client : sig
  type ('serv,'cli) t

  (* functions ... *)
end = struct
  type ('serv,'cli) t =
    { server: ('serv,'cli) Server.t
    ; (* other members ... *)
    }
end
and Server : sig
  type ('serv,'cli) t

  (* functions ... *)
end = struct
  type ('serv,'cli) t =
    { mutable clients: ('serv,'cli) Client.t list
    ; mutable state: 'serv
    }

  (* functions again ... *)
end
Run Code Online (Sandbox Code Playgroud)

这是我正在做的粗略近似(Client类型对象知道Server实例化它们Server.s知道它们的Clients).

当然,签名在重复.mli.为什么这有必要?

(注意:我不是在抱怨,但实际上想知道是否存在类型理论或"硬编译器问题"相关的原因.)

pho*_*oji 7

据我所知,没有办法解决这个问题.在很高的层次上,就编译器而言,Client的类型签名是完整的,直到它知道Server的类型签名,反之亦然.原则上,有一种解决方法:编译器可以在编译时交叉引用.mli文件.但是这种方法有缺点:它混合了编译器和链接器的一些职责,并使模块化编译(没有双关语意)更难.

如果您有兴趣,我建议Xavier Leroy 提出递归模块的原始建议.


ygr*_*rek 4

我的猜测:为了编译递归模块,编译器需要类型注释来实现。在 mli 文件(如果您使用任何)中,这些模块的类型可以进一步限制或完全隐藏,因此在一般情况下,编译器期望在 mli wrt 解析类型递归中找到有用的类型是不明智的。