OCaml:是否可以在单独的文件中定义相互递归的数据结构

时间:2017-02-22 15:29:02

标签: recursion module ocaml

我是OCaml的初学者。 我想知道如何在单独的文件中定义相互递归的数据类型。

我知道以下程序是合法的。

type t1 = A of int | B of t2
and  t2 = C of float | C of t1

现在,我想在其他文件中定义此t1t2以提高可读性(因为需要单独使用许多util函数)。

我也知道,我可以通过制作t1文件来定义t2.mli,并隐藏实施细节(只需写type t1type t2.mli个文件中。

但是,现在我不想隐藏它们。 有谁知道怎么做?

我希望简单的解决方案(不要使用复杂的或神奇的......)。

1 个答案:

答案 0 :(得分:8)

在OCaml的当前实现中,编译单元依赖图必须是非循环的。更简单地说,编译单元(即,不同的文件)不能相互递归地相互引用。

这种限制是一种过度近似,因为它不允许有效的程序,并且它与直觉相矛盾,因为可以在单个编译单元中编写递归模块。这种限制的原因来自递归模块的类型检查的复杂性。递归模块不能作为独立实体进行类型检查,因为它需要递归中涉及的整组模块。但OCaml独立的编译系统要求每个编译单元都是独立的和可键入的。如果OCaml没有使用单独的编译(并将程序作为一个整体链接),那么就可以实现递归单元。

部分解决方案是将接口的部分因素与相互递归无关,并在单独的模块中实现它们。例如,您可以按如下方式定义类型:

type 'b a = A of int | B of 'b
type 'a c = C of float | C of 'a
type t1 = t2 a and t2 = t1 c

现在,您可以为'b a定义界面的非循环部分。对于'b类型变量,该接口应该是通用的(换句话说,它不应该触及它)。在我们的示例中,很难想象这样的接口,但是,假设该示例是合成的,但对于产品类型,此方法将有意义(参见,type 'b a = {a : int; b : 'b} - 您可以实现与此相关的所有函数a字段)。

作为最后一点,我想说在实践中很少需要递归模块,并且通常表示设计中存在问题。特别是,当需要在单独的模块中移动定义时 - 这表明抽象没有被正确选择。当然,情况可能是根本问题本质上是复杂的,但这在现实生活中是非常罕见的。