Scala 这是尾部递归斐波那契函数尾部递归的定义吗?
我已经了解了延续传递型斐波那契函数的以下F#定义,我一直假设它是尾部递归函数:Scala 这是尾部递归斐波那契函数尾部递归的定义吗?,scala,f#,functional-programming,tail-recursion,continuation-passing,Scala,F#,Functional Programming,Tail Recursion,Continuation Passing,我已经了解了延续传递型斐波那契函数的以下F#定义,我一直假设它是尾部递归函数: 让fib k= 让我们继续= 匹配 |0 | 1->续1 |k->fib'(k-1)(乐趣a->fib'(k-2)(乐趣b->cont(a+b))) fib'k id 在Scala中尝试等效代码时,我使用了现有的@tailrec,当Scala编译器通知我递归调用不在尾部位置时,我措手不及: def fib(k: Int): Int = { @tailrec def go(k: Int, cont: In
让fib k=
让我们继续=
匹配
|0 | 1->续1
|k->fib'(k-1)(乐趣a->fib'(k-2)(乐趣b->cont(a+b)))
fib'k id
在Scala中尝试等效代码时,我使用了现有的@tailrec,当Scala编译器通知我递归调用不在尾部位置时,我措手不及:
def fib(k: Int): Int = {
@tailrec def go(k: Int, cont: Int => Int): Int = {
if (k == 0 || k == 1) cont(1)
else go(k-1, { a => go(k-2, { b => cont(a+b) })})
}
go(k, { x => x })
}
我相信我的Scala实现相当于F#one,所以我想知道为什么函数不是尾部递归的?JVM对尾部调用消除的支持是有限的 我不能说F#实现,但在scala中,您需要执行嵌套调用,因此它不处于尾部位置。考虑它的最简单方法是从堆栈的角度:当执行递归调用时,堆栈是否需要“记住”任何其他信息 在嵌套go调用的情况下,显然存在,因为内部调用必须在计算“返回”并完成外部调用之前完成 Fib可以递归定义如下:
def fib(k:Int) = {
@tailrec
def go(k:Int, p:Int, c:Int) : Int = {
if(k == 0) p
else { go(k-1, c p+c) }
}
go(k,0 1)
}
第4行对
go
的第二次调用不在尾部位置,它被包装在一个匿名函数中。(对于该功能,它处于尾部位置,但对于go
本身,它不处于尾部位置。)
对于连续传递样式,您需要适当的尾部调用,不幸的是Scala没有这样的尾部调用。(为了在JVM上提供PTC,您需要管理自己的堆栈,而不是使用破坏与其他语言互操作性的JVM调用堆栈,然而,互操作性是Scala的主要设计目标。)不幸的是,JVM还不支持尾部调用优化(?(公平地说,它有时可以优化某些调用)。Scala通过程序转换实现尾部递归优化(每个尾部递归函数相当于一个循环)。对于简单的递归函数来说,这通常就足够了,但相互递归或连续传递样式需要完全优化
当使用高级功能模式(如CPS或一元风格)时,这确实是个问题。为了避免炸毁堆栈,您需要使用。它可以工作,但这既不方便,也没有适当的尾部调用优化效率。这是一本很好的读物。在这种情况下,很容易找到不需要CPS的斐波那契函数的替代实现。那么,我应该如何在二叉搜索树中实现max/sum函数呢?除了简单的递归实现之外,我看到的唯一方法是使用堆栈(deque)。有什么想法吗?