尾递归函数(Coursera问题)

时间:2015-06-21 15:53:16

标签: scala syntax tail-recursion higher-order-functions

我正在学习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)不认为它是尾递归的。

这里总和称为尾递归,或者内部实现“循环”是在这种情况下被认为是尾递归的东西吗?

2 个答案:

答案 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不再关闭bf,但是你明白了。)