F#中来自不同文件的类型和函数之间的循环依赖关系问题 [英] Problem with cyclic dependencies between types and functions from different files in F#

查看:98
本文介绍了F#中来自不同文件的类型和函数之间的循环依赖关系问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前的项目使用的AST具有40种不同的类型(称为联合),并且该AST中的几种类型具有循环依赖性. 类型不是很大,因此我将它们放在一个文件中,并对相互依赖的类型应用了type ... and ...构造.

My current project uses AST with 40 different types (descriminated unions) and several types from this AST has cyclic dependency. The types are not so big, therefore I put them in one file and applied type ... and ... construction for mutually dependent types.

现在,我要添加函数以在AST中的每个元素下进行一些计算. 既然有很多功能,其中包含几行代码,为了使源代码更清晰可读,我将这些功能分离到了不同的文件中.

Now, I'm adding functions to make some calculations under each element in AST. Since, there are a lot of functions with several lines of code in them, to make source code cleaner to read, I've separated these functions in different files.

在没有循环依赖的情况下也可以,当依赖函数在同一文件中时也可以使用-在这种情况下,我可以使用let rec function1 ... and function2 ...构造

It's Ok in the case when cyclic dependency is absent, also works when dependent functions are in the same file - in this case I can use let rec function1 ... and function2 ... construction

但是对于我来说,它不起作用.

But it will not work in my case.

我还错误地认为签名文件可以帮助我解决这个问题,但是它们的行为不同于C ++ -它们用于定义函数/类型访问模式(内部/公共),也可以在此处添加函数/类型注释标题...

Also I incorrectly thought, that signature files can help me with this, but their behaviour differs from C++ - they are used to define functions/types access mode (internal/public), also functions/types comment header can be added here...

我看到的唯一可能的解决方案-将所有功能移至一个文件并使用let rec ... and ... and ... and ... and ...构造

The only possible solution I see - is to move all functions to one file and use let rec ... and ... and ... and ... and ... construction

可能有人有不同的想法吗?

谢谢.

推荐答案

如注释中所述,无法在多个文件之间拆分具有循环依赖性的函数(或类型).签名文件主要用于文档目的,因此无济于事.

As mentioned in the comments, there is no way to split functions (or types) with cyclic dependencies between multiple files. Signature files are useful mainly for documentation purposes, so they won't help.

很难给出一些建议,而又不知道确切的依赖关系是什么.但是,可以使用功能或接口重构实现的某些部分.例如,如果您有:

It is hard to give some advice without knowing what exactly the dependencies are. However, it may be possible to refactor some part of the implementation using functions or interfaces. For example, if you have:

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以将第二个函数用作参数.这样就可以在两个文件之间拆分实现,因为它们不再相互递归:

You can modify the function process1 to take the second function as argument. This makes it possible to split the implementation between two files because they are no longer mutually recursive:

// 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

如果您可以找到更清晰的结构-例如两个包含逻辑相关功能且需要相互访问的功能块,那么您还可以定义一个接口.对于仅具有两个函数的示例来说,这没有多大意义,但看起来像这样:

If you can find some more clear structure - e.g. two blocks of functions that contain logically related functions and need to access each other, then you can also define an interface. This doesn't make much sense for the example with just two functions, but it would look like this:

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

无论如何,这些只是一些通用技术.在不了解您正在使用的类型的情况下,很难给出更精确的建议.如果您可以共享更多详细信息,也许我们可以找到避免某些递归引用的方法.

Anyway, these are just some general techniques. It is difficult to give a more precise advice without knowing more about the types you're working in. If you could share more details, perhaps we could find a way to avoid some of the recursive references.

这篇关于F#中来自不同文件的类型和函数之间的循环依赖关系问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆