尾递归:比较两种情况

时间:2017-12-05 20:50:46

标签: scala recursion functional-programming stack-overflow

为什么这个尾递归:

pre

虽然不是这样:

  def navigate(myList : List[Int]) : (Int, List[Int]) = {
    def navigate(step: Int, offset: Int, myList: List[Int]): (Int, scala.List[Int]) = {
      if //some test and exit condition, then a definition of jump
      else navigate(step + 1, offset + jump, myList)
    }
    navigate(0, 0, myList)
  }

如果def navigate(myList : List[Int]) : (Int, List[Int]) = { navigate(0, 0, myList) } def navigate(step: Int, offset: Int, myList: List[Int]): (Int, scala.List[Int]) = { if //some test and exit condition, then a definition of jump else navigate(step + 1, offset + jump, myList) } 非常长,则第一种情况不会产生任何问题,而第二种情况会导致myList

另外,有没有办法说编译器应该编译后者,以便递归不会增加堆栈?

1 个答案:

答案 0 :(得分:4)

为了使方法符合尾递归优化的条件,它必须:

  • 是尾递归(呃!)
  • 不使用return
  • be final

你的两个例子都符合#1和#2,但只有第一个例子符合#3(本地方法是隐式最终的)。

如果方法不是final,那么方法不是尾递归的原因是“尾递归”意味着“尾调用自身”,但如果方法是虚拟的,那么你不能知道它是自己尾调用还是自我覆盖的版本。在编译时弄清楚方法是否被覆盖需要类层次结构分析,这已知等同于解决暂停问题... IOW是不可能的。

  

另外,有没有办法说编译器应该编译后者,以便递归不会增加堆栈?

没有。没有办法打开或关闭尾递归优化。尾递归的方法(根据Scala语言规范的“尾递归”的定义,当然)总是优化。任何不执行此操作的Scala实现都违反了Scala语言规范。

然而,scala.annotation.tailrec注释,它保证如果使用此注释注释的方法不符合SLS的尾部定义,编译器将生成错误-recursion。