我对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)并且它应该传递结果以便尾递归正确吗?我有点困惑。谢谢!
答案 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)
}