我是 OCaml 的初学者。
我想知道如何在单独的文件中定义相互递归的数据类型。
我知道以下程序是合法的。
type t1 = A of int | B of t2
and t2 = C of float | C of t1
现在,我想定义这个
t1
和 t2
在其他文件中以提高可读性(因为单独需要很多 util 函数)。我也知道,我可以定义
t1
和 t2
如上所述,通过制作 .mli
文件并隐藏实现细节(只需在 type t1
文件中写入 type t2
和 .mli
)。但是,现在我不想隐藏它们。
有谁知道该怎么做?
我希望简单的解决方案(不要使用复杂的或魔术的......)。
最佳答案
在当前的 OCaml 实现中,编译单元依赖图必须是非循环的。更简单地说,编译单元(即不同的文件)不能相互递归地相互引用。
这个限制是一个过度近似,因为它不允许有效的程序,并且它与直觉相矛盾,因为可以在单个编译单元中编写递归模块。这种限制的原因来自于递归模块类型检查的复杂性。递归模块不能作为独立实体进行类型检查,因为它需要递归中涉及的整个模块集。但是 OCaml 单独的编译系统要求每个编译单元都是独立的和可键入的。如果 OCaml 不使用单独的编译(并将程序作为一个整体链接),那么就有可能实现递归单元。
部分解决方案是将独立于相互递归的接口(interface)部分分解并在单独的模块中实现它们。例如,您可以按如下方式定义您的类型:
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
定义接口(interface)的非循环部分。这个接口(interface)对于 'b
类型变量应该是通用的(换句话说,它不应该接触它)。在我们的示例中,很难想象这样的接口(interface),但是,假设示例是合成的,但是对于产品类型,此方法将是有意义的(参见 type 'b a = {a : int; b : 'b
} - 您可以实现与 a
字段相关的所有功能)。作为最后一点,我想说递归模块在实践中很少需要,并且通常表示设计中存在问题。特别是,当需要在单独的模块中移动定义时——这表明没有正确选择抽象。当然,可能的情况是,潜在的问题本质上是复杂的,但这在现实生活中非常罕见。
关于recursion - OCaml:是否可以在单独的文件中定义相互递归的数据结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42395707/