Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 这是尾部递归斐波那契函数尾部递归的定义吗?_Scala_F#_Functional Programming_Tail Recursion_Continuation Passing - Fatal编程技术网

Scala 这是尾部递归斐波那契函数尾部递归的定义吗?

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

我已经了解了延续传递型斐波那契函数的以下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: 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)。有什么想法吗?