我有:
模块1 :
- 提供类型
Module1.type1
,其构造函数以及一些接受和返回type1
的功能
模块2 :
-
open Module1
-
open Module3
- 提供类型
Module2.type2
,还具有接受type1
和type3
作为params
的功能
模块3 :
-
open Module1
-
open Module2
- 提供依赖
type1
的 - 提供接受和返回类型
type1
,type2
和type3
的功能
Module3.type3
类型及其构造函数问题
因此,我显然会收到编译器的dependency cycle: src/Module3.cmj -> src/Module2.cmj -> src/Module3.cmj
错误。在与单个导入的打字稿/Js中可以实现的东西是不可能实现的。如何解决这个问题?
我真的不想更改程序的体系结构,只是为了促进编译器/模块系统的缺点。
处理问题的最简单方法确实是递归模块。我不建议您使用它们,因为递归模块可以使您的代码更难读取,编译,并且在最复杂的情况下可以在运行时破坏您的代码。更不用说您在模块定义中使用副作用(请不要(。
我将使用OCAML语法,您应该能够轻松地翻译成理性。
如果您无论如何都想使用它,这里是快速而肮脏的解决方案,使用递归模块和函子。
快速而肮脏的解决方案
1(创建一个模块mymodtypes,该模块将指示模块2和模块3的预期类型。它应该看起来像:
module type Module2type = sig ... end
module type Module3type = sig ... end
...
是模块的预期签名(如果您已经写了接口文件,只需在此处复制/粘贴它们,如果您不写这些,则很重要(
2(将模块2和模块3放入函子中,期望其他模块
例如,Module2的代码现在看起来像
module MakeModule2(Module3 : MyModTypes.Module3type) = struct
(* the code of module2 *)
end
模块3的代码将以相同的方式,只需在添加行中交换2和3。
3(用该代码创建一个模块makemodules2and3(转换为理性(:
module rec Module2 : MyModTypes.Module2type = Module2.MakeModule2(Module3)
and Module3 : MyModTypes.Module3type = Module3.MakeModule3(Module2)
请注意,递归模块定义总是期望模块类型。
4(Module2
和Module3
的随后使用现在应该在能够使用它们之前open Makemodules2and3
。
正确的解决方案
您必须更改程序的体系结构。略微。
正如OP所说,功能没有依赖性的循环,这是一种缓解。只需将模块2和模块3分为两个新模块即可。一个仅取决于模块1及其模块的功能,一个具有"下一步"功能。
这是一种更好的方法来宣布模块的方式:它们应该是定义的类型的方法。理想情况下,您为每种类型都有一个模块,以及类型之间的每种相互作用的附加模块。
看起来Module1
不取决于其他两个模块。您可以保持原样。但是,由于其他两个是相互递归的,因此您可以使用递归模块语法表达。尽管您在定义点声明了模块签名,但这确实有一个要求,因为理性需要知道期望什么。例如:
/* Impl.re */
module rec Module2: {
type type2;
let make: (Module1.type1, Module3.type3) => type2;
} = {
... actual implementation of Module2 ...
} and Module3: {
type type3;
let make: Module1.type1 => type3;
let foo: Module1.type1;
let bar: Module2.type2 => type3;
} = {
... actual implementation of Module3 ...
};
这是您要使用的一般形状,您可以根据需要调整它。
如果您不希望用户必须执行Impl.Module2....
访问递归模块,甚至可以使用include
将其曝光为文件模块:
/* Module2.re */
include Impl.Module2;
,您甚至可以通过编译时间警告来注释实现模块(Impl.Module2
和3(,以使用户知道不要使用这些模块:
/* Impl.re */
[@deprecated "Please use Module2 instead of Impl.Module2"]
module Module2: {...} = {...};