nom*_*ddo 6 recursion ocaml module
我是OCaml的初学者.我想知道如何在单独的文件中定义相互递归的数据类型.
我知道以下程序是合法的.
type t1 = A of int | B of t2
and t2 = C of float | C of t1
Run Code Online (Sandbox Code Playgroud)
现在,我想这个定义t1并t2在可读性其他文件(因为被需要来逐个很多util的功能).
我也知道,我可以定义t1并t2通过使作为上述.mli文件和隐藏实现细节(只写type t1和type t2在.mli文件).
但是,现在我不想隐藏它们.有谁知道怎么做?
我希望简单的解决方案(不使用复杂或魔术......).
在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
Run Code Online (Sandbox Code Playgroud)
现在,您可以为界面定义非循环部分'b a.这个接口应该是关于'b类型变量的通用(换句话说,它不应该触摸它).在我们的示例中,很难想象这样的接口,但是,假设该示例是合成的,但对于产品类型,此方法将有意义(参见,type 'b a = {a : int; b : 'b} - 您可以实现与该a字段相关的所有函数).
最后,我想说实际上很少需要递归模块,通常表示设计中存在问题.特别是,当需要在单独的模块中移动定义时 - 这表明抽象没有被正确选择.当然,情况可能是根本问题本质上是复杂的,但这在现实生活中是非常罕见的.