我当前的项目使用具有 40 种不同类型(可区分联合)的 AST,并且该 AST 中的几种类型具有循环依赖关系。
类型不是很大,因此我将它们放在一个文件中并应用type ... and ...
相互依赖类型的构造。
现在,我添加函数来对 AST 中的每个元素进行一些计算。
由于有很多函数,其中有几行代码,为了使源代码更清晰易读,我将这些函数分离在不同的文件中。
在不存在循环依赖的情况下没问题,当依赖函数位于同一个文件中时也可以工作 - 在这种情况下我可以使用let rec function1 ... and function2 ...
建造。
但它不适用于我的情况。
另外,我错误地认为签名文件可以帮助我解决这个问题,但它们的行为与 C++ 不同
- 它们用于定义函数/类型访问模式(内部/公共),也可以在此处添加函数/类型注释头。
我看到的唯一可能的解决方案是将所有函数移至一个文件并使用let rec ... and ... and ... and ... and ...
建造。
可能有人有不同的想法?
正如评论中提到的,无法在多个文件之间分割具有循环依赖关系的函数(或类型)。签名文件主要用于文档目的,因此没有帮助。
如果不知道确切的依赖关系是什么,就很难给出一些建议。但是,可以使用函数或接口重构实现的某些部分。例如,如果您有:
let rec process1 (a:T1) =
match a with
| Leaf -> 0
| T2Thing(b) -> process2 b
and process2 (b:T2) =
match b with
| T1Thing(a) -> process1 a
您可以修改该功能process1
将第二个函数作为参数。这使得可以在两个文件之间分割实现,因为它们不再相互递归:
// File1.fs
let process1 (a:T1) process2 =
match a with
| Leaf -> 0
| T2Thing(b) -> process2 b
// File2.fs
let rec process2 (b:T2) =
match b with
| T1Thing(a) -> process1 a process2
如果你能找到一些更清晰的结构 - 例如两个功能块包含逻辑上相关的功能并且需要互相访问,那么也可以定义一个接口。对于只有两个函数的示例来说这没有多大意义,但它看起来像这样:
type IProcess2 =
abstract Process : T2 -> int
let process1 (a:T1) (process2:IProcess2) =
match a with
| Leaf -> 0
| T2Thing(b) -> process2.Process b
let rec process2 (b:T2) =
let process2i =
{ new IProcess2 with
member x.Process(a) = process2 a }
match b with
| T1Thing(a) ->
process1 a process2i
无论如何,这些只是一些通用技术。如果不了解您正在使用的类型,则很难给出更准确的建议。如果您可以分享更多详细信息,也许我们可以找到一种方法来避免一些递归引用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)