尾递归 - Scala(任何其他语言)

时间:2017-05-10 15:14:01

标签: scala recursion tail-recursion

我对Tail递归有疑问。据我所知Tail递归是函数的最后一次递归调用将传递函数的结果。但是当我有这样的功能时

def func1(n: Int): Int = {
   if (n > 100) {
      n - 10
   }
   else {
      func1(func1(n + 11))
   }
}

会是尾递归吗?例如

func1(100) = func1(func1(111)) = func1(101) = 91

所以最后一次递归调用将是func1(101)并且它应该传递结果以便尾递归正确吗?我有点困惑。谢谢!

4 个答案:

答案 0 :(得分:4)

这不是尾递归。您可以将代码重写为:

def func1(n: Int): Int = {
   if (n > 100) {
      n - 10
   }
   else {
      val f = func1(n + 11)
      func1(f)
   }
}

你可以看到第6行的func1调用不在尾部位置。

答案 1 :(得分:4)

任何简单的方法都可以尝试。如果你的方法不是尾递归的话,@ tailrec注释(import scala.annotation.tailrec)会给你一个编译时错误。

这不是尾递归,因为你在非尾部位置有一个递归调用。

你的函数中有两个递归调用,一个处于尾部位置,它是方法中的最后一个调用,但另一个是该调用的输入,它不是递归的,因为它不是递归的。接下来是接下来的电话。在尾部位置进行一次递归调用是不够的,每次递归调用都必须是尾调用

答案 2 :(得分:0)

不,你的例子不是尾递归的情况。

func1(func1(n + 11))是一种非线性递归(特别是嵌套递归)。

尾递归是线性递归的一个特例,可以立即转换为迭代(循环),这就是为什么它很有趣,因为它允许简单的优化。

在你的情况下,对内部函数的调用不是函数中的最后一个操作(仍有待调用外部函数),因此,它不是尾递归。

答案 3 :(得分:0)

实际上,tail递归方法是一种“返回”结果本身或下一次调用的方法。如果您可以通过以下方式重写算法 - 它可以是尾递归。

trait Recursive[R] {
  def oneIteration: Either[R, Recursive[R]]
}

object Recursive {
  def interpret[R](fn: Recursive[R]): R = {
    var res: Either[R, Recursive[R]] = Right(fn)
    while(res.isRight) {
      res = res.right.get.oneIteration
    }
    res.left.get
  }
}

object Factorial extends App {
  def factorial(acc: BigDecimal, n: Int): Recursive[BigDecimal] = new Recursive[BigDecimal] {
    override def oneIteration(): Either[BigDecimal, Recursive[BigDecimal]] = {
      if(n == 1 ){
        Left(acc)
      }
      else {
        Right(factorial(acc * n, n - 1))
      }
    }
  }

  val res = Recursive.interpret(factorial(1 , 5))
  println(res)
}