【问题标题】:Scala compiler doesn't recognize tail recursionScala 编译器无法识别尾递归
【发布时间】:2021-11-23 13:53:03
【问题描述】:

我正在尝试使用尾递归创建毕达哥拉斯三元组,但即使我没有在 return 语句中进行任何计算,编译器似乎也无法识别它。

错误代码是这样的:Cannot rewrite recursive call: it is not in tail position

这是尾递归的代码:

  def tailPythagorean(positiveNumber: Int): List[(Int, Int, Int)] = {
  return tailRunner(positiveNumber, positiveNumber, List())
    .take(positiveNumber);
  }

  @tailrec def tailRunner(biggerNumber: Int, smallerNumber: Int, list: List[(Int, Int, Int)]): List[(Int, Int, Int)] = {
    if (biggerNumber == 0 || smallerNumber == 0) {
      return list;
    }

    val smallNumber = if (smallerNumber == 1) biggerNumber - 1 else smallerNumber - 1;
    
    return tailRunner(biggerNumber, smallNumber, List((((biggerNumber + 1) * (biggerNumber + 1) - (smallerNumber * smallerNumber)), (2 * (biggerNumber + 1) * smallerNumber), ((biggerNumber + 1) * (biggerNumber + 1) + (smallerNumber * smallerNumber)))) ::: list);
  }

这里是未针对尾递归优化的递归解决方案的代码(供参考):

def recursivePythagorean(positiveNumber: Int): List[(Int, Int, Int)] = {
  return recursiveRunner(positiveNumber, positiveNumber)
    .take(positiveNumber);
  }

  def recursiveRunner(biggerNumber: Int, smallerNumber: Int): List[(Int, Int, Int)] = {
    if (biggerNumber == 0 || smallerNumber == 0) {
      return List();
    }
    if (smallerNumber == 1) {
      return recursiveRunner(biggerNumber - 1, biggerNumber - 1) ::: List((((biggerNumber + 1) * (biggerNumber + 1) - (smallerNumber * smallerNumber)), (2 * (biggerNumber + 1) * smallerNumber), ((biggerNumber + 1) * (biggerNumber + 1) + (smallerNumber * smallerNumber))));
    }
    else {
      return recursiveRunner(biggerNumber, smallerNumber - 1) ::: List((((biggerNumber + 1) * (biggerNumber + 1) - (smallerNumber * smallerNumber)), (2 * (biggerNumber + 1) * smallerNumber), ((biggerNumber + 1) * (biggerNumber + 1) + (smallerNumber * smallerNumber))));
    }
  }

编辑:根据@AminMal 和@Jörg W Mittag 的cmets,确实是return 关键字的存在使编译器抱怨。删除它们为我修复了它:

  def tailPythagorean(positiveNumber: Int): List[(Int, Int, Int)] = {
    tailRunner(positiveNumber, positiveNumber, List())
      .take(positiveNumber);
  }

  @tailrec def tailRunner(biggerNumber: Int, smallerNumber: Int, list: List[(Int, Int, Int)]): List[(Int, Int, Int)] = {
    if (biggerNumber == 0 || smallerNumber == 0) {
      return list;
    }
    if (smallerNumber == 1) {
      tailRunner(biggerNumber - 1, biggerNumber - 1, List((((biggerNumber + 1) * (biggerNumber + 1) - (smallerNumber * smallerNumber)), (2 * (biggerNumber + 1) * smallerNumber), ((biggerNumber + 1) * (biggerNumber + 1) + (smallerNumber * smallerNumber)))) ::: list);
    }
    else {
      tailRunner(biggerNumber, smallerNumber - 1, List((((biggerNumber + 1) * (biggerNumber + 1) - (smallerNumber * smallerNumber)), (2 * (biggerNumber + 1) * smallerNumber), ((biggerNumber + 1) * (biggerNumber + 1) + (smallerNumber * smallerNumber)))) ::: list);
    }
  }

【问题讨论】:

  • 尝试将tailrec函数的最后两行放在else块中,另外,最好不要使用return关键字,你不是必须这样做:)
  • 您的 tailrec 代码为我编译没有错误(Scala 2.13.3)。顺便说一句,经验丰富的 Scala 程序员永远不会,永远,使用returnHere's why.
  • 另外,tailRunner() 不是 recursiveRunner() 算法的准确实现:biggerNumber 实际上从未递减。
  • 很好地抓住了逻辑错误@jwvh!根据this answer,我认为它为您编译没有错误,因为@tailrec 标志是在 Scala 2.8 中提出的

标签: scala recursion tail-recursion scala-3 pythagorean


【解决方案1】:

尾递归方法和局部函数不允许使用return进行尾递归调用。只需从最后一行删除 return 关键字即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-07
    • 2018-03-17
    相关资源
    最近更新 更多