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

时间:2011-01-20 04:59:36

标签: module ocaml 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

这是我正在做的事情的粗略近似(Client类型对象知道实例化它们的ServerServer知道他们的Client s。 / p>

当然,签名会在.mli中重复出现。为什么这有必要?

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

2 个答案:

答案 0 :(得分:7)

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

如果您有兴趣,我推荐Xavier Leroy的original proposal用于递归模块。

答案 1 :(得分:4)

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