对于F#中的递归,现有文档很清楚如何在特殊情况下执行它,它只是一个函数调用自身,或者是一组物理上相邻的函数相互调用。
但是在一般情况下,不同模块中的一组功能需要相互调用,你是如何做到的?
答案 0 :(得分:7)
我认为在F#中无法实现这一目标。通常可以以不需要的方式构建应用程序,因此,如果您描述了自己的场景,可能会得到一些有用的注释。
无论如何,有多种方法可以解决此问题 - 您可以声明记录或接口来保存从模块导出所需的功能。接口允许您导出多态函数,因此它们可能是更好的选择:
// Before the declaration of modules
type Module1Funcs =
abstract Foo : int -> int
type Module2Funcs =
abstract Bar : int -> int
然后,模块可以导出一个实现其中一个接口和函数的值,这些接口和函数需要另一个模块将其作为参数(或者您可以将其存储在可变值中)。
module Module1 =
// Import functions from Module2 (needs to be initialized before using!)
let mutable module2 = Unchecked.defaultof<Module2Funcs>
// Sample function that references Module2
let foo a = module2.Bar(a)
// Export functions of the module
let impl =
{ new Module1Funcs with
member x.Foo(a) = foo a }
// Somewhere in the main function
Module1.module2 <- Module2.impl
Module2.module1 <- Module1.impl
初始化也可以使用Reflection自动完成,但这有点难看,但如果你真的经常需要它,我可以想象为此开发一些可重用的库。
在许多情况下,这感觉有点难看并且重构应用程序以避免递归引用是一种更好的方法(实际上,我发现面向对象编程中的类之间的递归引用通常非常混乱)。但是,如果你确实需要这样的东西,那么使用接口/记录导出函数可能是唯一的选择。
答案 1 :(得分:0)
我认为不同模块中的函数可以直接引用其他模块中的函数。行为如此紧密交织的函数是否需要在单独的模块中?
如果你需要将它们分开,一种可能的解决方法是使你的函数更高阶,以便它们采用表示递归调用的参数,这样你就可以在以后手动“打结”。
答案 2 :(得分:0)
如果你在谈论C#,并且两个不同程序集中的方法需要相互递归地相互调用,我会将他们需要知道的类型签名拉出到第三个共享的程序集中。然而,我不知道这些概念与F#有多好关系。
答案 3 :(得分:0)
这里明确的解决方案将使用模块签名。签名文件包含有关一组F#程序元素(例如类型,名称空间和模块)的公共签名的信息。 对于每个F#代码文件,您可以都有一个签名文件,该文件的名称与代码文件相同,但扩展名为.fsi而不是.fs。
答案 4 :(得分:-1)
不支持此功能。一个证据是,在视觉stuido中,您需要为F#正确订购项目文件。
recursively
在两个不同的模块中调用两个函数真的很少见。
如果确实发生了这种情况,你最好将两个功能的共同部分考虑在内。