Scala和尾递归

时间:2009-11-09 18:27:58

标签: scala tail-recursion

Stack Overflow上有各种答案,它解释了Scala中尾递归的条件。我理解限制以及如何以及在哪里可以利用尾递归。我不明白的部分是为什么存在对私有或最终方法的限制。

我还没有研究Scala编译器如何在字节码级别将递归函数实际转换为非递归函数,但我们假设它执行类似下面的操作。我有一个带有递归函数Foo的类mod

class Foo {
  def mod(value: Int, denom: Int): Int = {
    if(denom <= 0 || value <= 0) 0
    else if(0 <= value && value < denom) value
    else mod(value - denom, denom)
  }
}

这是一个基本的模数函数,我想Scala编译器转换为某种伪Java-Scala,如:

class Foo {
  def mod(value: Int, denom: Int): Int = {
    if(denom <= 0 || value <= 0) return 0
    while(value > denom) value -= denom
    return value
  }
}

(我可以相信我搞砸了那个翻译,但我不认为细节很重要。)

所以现在假设我是Foo的子类:

class Bar extends Foo {
  def mod(value:Int, denom: Int): Int = 1
}

是什么阻止了它的工作?当JVM调用Foo/Bar并调用mod时,为什么解析应该使用的mod函数会出现问题。为什么这与基函数是非递归的情况有什么不同?

我可以看到的一些可能的原因是:

  1. 无论出于什么原因,Scala编译器的实现都没有处理这个问题(如果是这样的话就足够公平。如果是这样,是否有计划改变它?)

  2. {li>

    Foo mod函数在编译期间被mod-non-recursive传递给Foo,因此mod实际上没有{{1}}方法来覆盖。

2 个答案:

答案 0 :(得分:8)

我刚刚回答了这个问题,但让我们举个例子。假设您定义了类Foo,并将其作为JAR文件提供。

然后我得到那个Jar文件,并以这种方式扩展你的Foo:

class Bar extends Foo {
  def mod(value:Int, denom: Int): Int = {
    Logger.log("Received mod with "+value+" % "+denom)
    super.mod(value, denom)
}

现在,当Foo的mod调用自身时,因为我的对象是Bar,而不是Foo,你应该(并且确实)去 Bar's mod,而不是Foo的。

因为这是真的,你无法按照你所展示的方式对其进行优化。

子类的合约是,当超类在自身上调用方法时,如果该方法被覆盖,则它将是要调用的子类'方法。

将方法声明为private,使其成为final或类 - 甚至创建递归函数而不是方法,所有这些都确保您不必去子类实现。

答案 1 :(得分:-1)

IttayD今天早些时候刚问过这个问题。答案是Foo的尾部递归只会在you can't override mod in subclasses时进行优化(因为该类是最终的,或者因为该方法是最终的或私有的。)