【问题标题】:Not able to write a method in Tail Recursion in Scala无法在 Scala 的尾递归中编写方法
【发布时间】:2014-07-08 19:30:10
【问题描述】:

我有一个函数:

@tailrec
def sampleTailRec(list: List[Int]) : List[Int] = {
  if(list.nonEmpty) {
    val value: Int = list.head * 2
    List(value) ++ sampleTailRec(list.drop(1))
  } else {
    List()
  }
}

这给了我以下编译错误

无法优化 @tailrec 注释方法 sampleTailRec:它包含一个不在尾部位置的递归调用 List(value) ++ sampleTailRec(list.drop(1))

我曾尝试用尾递归编写代码

无法理解为什么我的代码不在尾递归中以及如何使此方法尾递归?

【问题讨论】:

    标签: scala tail-recursion


    【解决方案1】:

    您的方法sampleTailRec 不是尾递归的。

    只有当递归调用是方法返回之前发生的最后一件事时,方法才是尾递归的。在您的方法中并非如此。看这一行:

    List(value) ++ sampleTailRec(list.drop(1))
    

    想想当这行代码执行时会发生什么:

    • 首先,评估list.drop(1)
    • 然后递归调用方法:sampleTailRec(list.drop(1))
    • 然后将其结果附加到List(value)

    注意在递归调用之后执行的还有一个步骤——递归调用的结果用于确定最终结果。

    【讨论】:

    • 感谢 Jesper 将其分解。它帮助我理解了为什么我的方法不是尾递归的。
    【解决方案2】:

    尾递归调用不会在任何后续操作中修改(或使用)递归调用的结果。您的示例在添加 List(value) 之前执行此操作。这抑制了优化。通常,您可以通过调用传递更多状态来实现尾递归。

    【讨论】:

      【解决方案3】:

      如果我的理解是正确的,你正在尝试将列表中的每个元素乘以 2,看看这个:

      $ scala
      Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05).
      Type in expressions to have them evaluated.
      Type :help for more information.
      
      scala>   @scala.annotation.tailrec
           |   def sampleTailRec(list: List[Int], accumulator: List[Int] = List.empty[Int]) : List[Int] = {
           |     list match {
           |       case Nil => accumulator.reverse
           |       case head :: Nil => sampleTailRec(Nil, head * 2 :: accumulator)
           |       case head :: tail => sampleTailRec(tail, head * 2 :: accumulator)
           |     }
           |   }
      sampleTailRec: (list: List[Int], accumulator: List[Int])List[Int]
      
      scala> sampleTailRec(1 to 10 toList)
      warning: there were 1 feature warning(s); re-run with -feature for details
      res0: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
      

      【讨论】:

        【解决方案4】:

        您可以将您的方法转换为以下方法,它以您想要的方式使用尾递归,并且具有相同的(线性)复杂性:

        def sampleTailRec(list:List[Int]): List[Int] = {
          @tailrec
          def sampleTailRec_aux(l: List[Int], result: List[Int]): List[Int] = {
           if (l.nonEmpty) sampleTailRec_aux(l.tail, (l.head * 2) :: result)
           else result.reverse
          }
          sampleTailRec_aux(list, List())
        }
        

        【讨论】:

        • 谢谢。该代码有助于理解如何进行尾递归。
        猜你喜欢
        • 2021-11-23
        • 2012-05-04
        • 2018-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-17
        • 1970-01-01
        • 2018-03-08
        相关资源
        最近更新 更多