我正在学习Scala中的函数式编程Coursera课程,以便我可以学习该语言。
他们引入了尾递归函数的概念,并将它们定义为一个以对自身调用结束的函数。但后来他们将此作为一个有效的例子:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
def loop(a: Int, acc: Int): Int = {
if (a > b) acc
else loop(a + 1, f(a) + acc)
}
loop(a, 0)
}
如果我用@tailrec注释总和,我会收到错误,因为IDE(IntelliJ)不认为它是尾递归的。
这里总和称为尾递归,或者内部实现“循环”是在这种情况下被认为是尾递归的东西吗?
答案 0 :(得分:2)
你是对的。 sum
需要自称,否则Scala会抱怨:
@tailrec annotated method contains no recursive calls
如果告诉编译器确切的位置,可以将@tailrec
移动到尾递归的位置:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
@tailrec def loop(a: Int, acc: Int): Int = {
if (a > b) acc
else loop(a + 1, f(a) + acc)
}
loop(a, 0)
}
然后编译器会感到满意,它是尾递归优化的。
答案 1 :(得分:1)
内部loop
方法是尾递归的,sum
方法根本不是递归的。因此,您应该使用loop
注释@tailrec
。
将loop
移至外部范围可能有助于查看正在发生的事情:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
loop(a, 0)
}
def loop(a: Int, acc: Int): Int = {
if (a > b) acc
else loop(a + 1, f(a) + acc)
}
如您所见,sum
仅仅是loop
的公共入口点。
(请注意,上面的代码不会被编译,因为loop
不再关闭b
或f
,但是你明白了。)