Scala 和尾递归

发布于 2024-08-10 01:39:45 字数 1364 浏览 4 评论 0原文

Stack Overflow 上有各种答案,解释了 Scala< 中可以进行尾递归的条件/a>.我了解其局限性以及如何以及在何处可以利用尾递归。我不明白的是为什么存在对私有或最终方法的限制。

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

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. in Foo mod 函数在编译期间被修改为 mod-non-recursive,因此 Foo 实际上没有 mod > 要重写的方法。

There are various answers on Stack Overflow which explain the conditions under which tail recursion is possible in Scala. I understand the limitations and how and where I can take advantage of tail recursion. The part I don't understand is why the limitation to private or final methods exists.

I haven't researched how the Scala compiler actually converts a recursive function to a non-recursive one at a bytecode level, but let's assume it does something like the following. I have a class Foo with a recursive function 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)
  }
}

That's a basic modulo function which I imagine the Scala compiler translates to some kind of pseudo-Java-Scala like:

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

(I can believe I've messed up that translation but I don't think the details are important..)

So now suppose I subclass Foo:

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

What it is that stops this from working? When the JVM has a Foo/Bar and mod is called on it, why is there a problem with resolving the mod function that should be used. Why is this any different from the situation where the base function is non-recursive?

A few possible reasons I can see for this being the case are:

  1. for whatever reason the implementation of the Scala compiler doesn't handle this (fair enough if that is the case. If so, are there plans to change this?)

  2. in Foo the mod function is munged to mod-non-recursive during compilation so Foo doesn't actually have a mod method to override.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

じее 2024-08-17 01:39:45

我刚刚回答了这个问题,但让我们举个你自己的例子。假设您定义了 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< /code>,你应该(并且确实)去 Bar's mod,而不是 Foo's。

因为这是事实,所以您无法按照您所展示的方式对其进行优化。

子类化的契约是,当超类调用自身的方法时,如果该方法已被重写,则将调用子类的方法。

将方法声明为私有,使其成为最终方法或类,甚至创建一个递归函数而不是方法,所有这些都确保您不必使用子类实现。

I have just answered that, but let's take your own example. Say you defined that class Foo, and made it available as a JAR file.

Then I get that Jar file, and extend your Foo this way:

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

Now, when Foo's mod calls itself, because my object is a Bar, not a Foo, you are supposed (and do) go to Bar's mod, not to Foo's.

And because that is true, you can't optimize it the way you have shown.

It is the CONTRACT of subclassing that, when a super class calls a method on itself, if that method has been overridden it will be the subclass' method to be invoked.

Declaring the method private, making it final, or the class -- or even making a recursive function instead of a method, all insure you won't potentially have to go to a subclass implementation.

慕烟庭风 2024-08-17 01:39:45

IttayD 今天早些时候刚刚问过这个问题。答案是,只有当你不能在子类中重写 mod 时,Foo 的尾递归才会被优化 (因为类是最终的,或者因为方法是最终的或私有的。)

IttayD just asked this question earlier today. The answer is that Foo's tail recursion will only be optimized if you can't override mod in subclasses (be that becuase the class is final, or because the method is final or private.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文