如何让两种方法相互呼叫?

Dmi*_*ruk 34 f# mutual-recursion

关于如何让两个方法相互呼叫(即有A()呼叫B()B()呼叫A()),我有点困惑.似乎F#只在代码中遇到它后"看到"该方法,所以如果它没有,它只是说值或构造函数尚未定义.

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

Bri*_*ian 44

'让rec ......和......'是你寻求的语法.

let rec F() = 
    G()
and G() =
    F()
Run Code Online (Sandbox Code Playgroud)

另见F#Co-Recursion中的冒险.

  • @ozgur 假设您想创建一个 JSON 解析器。然后你需要一个函数来解析元素可以是对象的列表。并且您需要一个函数来解析其值可以是列表的对象。这种类型的递归并不像您想象的那么罕见。 (2认同)

Kur*_*out 21

既然问题是关于方法的,而Brian的答案是关于函数的,那么指出你可以对类型使用类似的语法是有用的:

type A() =
    let b = new B()
    member x.MethodA() = b.MethodB()
and B() =
    member x.MethodB() = ()
Run Code Online (Sandbox Code Playgroud)

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


Van*_*oiy 6

通过 let 声明的函数

let rec a () = b ()
and b () = ()
Run Code Online (Sandbox Code Playgroud)

这些是相互递归的函数

同类型中的方法

type T () =
    member t.A () = t.B()
    member t.B () = ()
Run Code Online (Sandbox Code Playgroud)

这是微不足道的;它只是有效。不过请注意 Abel 的评论。

不同类型中的方法

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

and TypeB () =
    member b.B () = ()
Run Code Online (Sandbox Code Playgroud)

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

笔记

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

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


Sha*_*tin 6

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

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

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

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

    let ping () = 
        printfn "ping"
        pong()
Run Code Online (Sandbox Code Playgroud)

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