允许@tailrec在调用多个递归调用时的结构

时间:2015-07-12 00:44:14

标签: scala recursion tail-recursion

以下逻辑标识了总和为 n 的整数组合,产生最大乘积:

def bestProd(n: Int) = {
  type AType = (Vector[Int],  Long)
  import annotation._
  // @tailrec  (umm .. nope ..)
  def bestProd0(n: Int, accum : AType): AType  = {
    if (n<=1) accum
    else {
      var cmax = accum
      for (k <- 2 to n) {
        val tmpacc = bestProd0(n-k, (accum._1 :+ k, accum._2 * k))
        if (tmpacc._2 > cmax._2) {
          cmax = tmpacc
        }
      }
      cmax
    }
  }
  bestProd0(n, (Vector(), 1))
}

此代码确实有效:

scala> bestProd(11)
res22: (Vector[Int], Long) = (Vector(2, 3, 3, 3),54)

现在,@tailrec不起作用对我来说并不奇怪。毕竟所有递归调用在尾部位置。有可能重新构造 for 循环而不是进行适当的单次调用来实现尾递归吗?

1 个答案:

答案 0 :(得分:1)

如果您试图坚持所述算法,我认为这是不可能的。重新思考方法,你可以做这样的事情。

import scala.annotation.tailrec
def bestProd1(n: Int) = {
  @tailrec
  def nums(acc: Vector[Int]): Vector[Int] = {
    if (acc.head > 4)
      nums( (acc.head - 3) +: 3 +: acc.tail )
    else
      acc
  }
  val result = nums( Vector(n) )
  (result, result.product)
}

它提供了相同的结果(据我所知),除了我没有将4分成2,2