如何实现两个方法相互调用?

39

我有些困惑如何让两个方法相互调用(例如,让A()调用B(),并使B()调用A())。似乎 F# 只有在代码中遇到方法后才会“看到”它,因此如果没有遇到它,它就会显示“值或构造函数未定义”的错误信息。

我是否漏掉了一些非常基础的东西?

4个回答

47

你需要寻找的语法是'let rec... and...'。

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

另请参阅F#共递归探险


最佳解决方案是避免出现A()调用B(),B()再调用A()的情况。如果我们确实需要这样做,那么我们的功能设计可能存在问题。理想情况下,我们不应该遇到这种情况。如果我说错了,请纠正我。 - ozgur
2
@ozgur 假设你想创建一个JSON解析器。那么你需要一个函数来解析列表,其元素可以是对象。你还需要一个函数来解析值为列表的对象。这种递归类型并不像你想象的那么罕见。 - The Hoff

22

因为问题是关于方法的,而Brian的答案是关于函数的,也许指出你可以使用类似的语法来定义类型会很有用:

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

需要注意的是,默认情况下成员被视为 'let rec'(事实上,我认为它们不能不递归)。


10

F# 4.1 引入了相互递归模块和命名空间,这是 and 关键字的一种替代方案。

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

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

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

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


6

Functions declared via let

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

这些是相互递归的函数

同一类型中的方法

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

这很简单,它只是有效的。请注意Abel的评论。

不同类型内的方法

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

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

这使用了type ... and语法来定义互递归类型

注释

通常情况下,只有在两个方向上都需要调用时才使用and。否则,重新排序声明使被调用的函数先出现可能更好。避免循环依赖并在不使用它们的地方不暗示它们可以帮助类型推断和可读性。

我建议编辑问题,要求提供一般函数或不同类型(在这种情况下,我将从此答案中删除前两种情况)。方法通常被认为是函数的子集,这是一般数学术语。然而,所有F#函数在技术上都是CLI方法,因为它们编译成这样。目前,不清楚问题正在询问什么,但我假设从已接受的答案中得知,它不仅仅要求方法,正如标题所示。


1
在“不同类型内的方法”中,您说它是“微不足道的;它只是起作用”,但有一个细节很容易被忽视:当您使用inline和/或某些成员约束时,可能需要按顺序声明它们(即,反向引用将产生奇怪且难以诊断的错误)。请参见错误报告类型成员的顺序是相关的 - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接