39

对于如何让两种方法互相调用(即有A()callB()B()call A()),我有点困惑。似乎 F# 仅在代码中遇到该方法后才“看到”该方法,因此如果没有,它只会说value 或 constructor has not been defined

我在这里错过了一些非常基本的东西吗?

4

4 回答 4

47

'let rec... and...' 是您寻求的语法。

let rec F() = 
    G()
and G() =
    F()

另请参阅F# Co-Recursion 中的冒险

于 2009-03-25T08:02:29.027 回答
22

由于问题是关于方法的,而 Brian 的答案是关于函数的,所以指出您可以对类型使用类似的语法可能很有用:

type A() =
    let b = new B()
    member x.MethodA() = b.MethodB()
and B() =
    member x.MethodB() = ()

另请注意,默认情况下成员是'let rec'(实际上我认为他们不能不递归)。

于 2009-03-25T08:14:20.793 回答
9

F# 4.1 引入了相互递归的模块和命名空间

这些是and关键字的替代品。

module rec PingPong = // <------ rec keyword here.

    let pong() = 
        printfn "pong"
        ping() 

    let ping () = 
        printfn "ping"
        pong()

rec关键字定义了“允许所有包含的代码相互递归”的模块和命名空间。

于 2018-02-23T05:08:39.307 回答
6

通过 let 声明的函数

let rec a () = b ()
and b () = ()

这些是相互递归的函数

同一类型内的方法

type T () =
    member t.A () = t.B()
    member t.B () = ()

这是微不足道的;它只是工作。请注意亚伯的评论。

不同类型中的方法

type TypeA () =
    member t.A (b : TypeB) = b.B()

and TypeB () =
    member b.B () = ()

这使用了相互递归类型type ... and的语法。

笔记

通常,and仅在呼叫发生在两个方向时使用。否则,最好重新排序声明,以便被调用的函数首先出现。避免循环依赖并在不使用它们的地方不暗示它们通常有助于类型推断和可读性。

我建议编辑这个问题,要么要求一般的功能,要么要求不同的类型(在这种情况下,我会从这个答案中删除前两种情况)。方法通常被认为是函数的子集,这是通用的数学术语。但是,从技术上讲,所有 F# 函数都是CLI 方法,因为它们是编译成的。照原样,目前尚不清楚问题的要求是什么,但我从接受的答案中假设它不仅要求方法,正如标题所暗示的那样。

于 2014-11-07T19:39:55.047 回答