使用yield时使scala函数尾递归?

时间:2016-05-04 20:22:44

标签: scala recursion tail-recursion

我有一个正在运作的功能;

def iterate(start: Seq[TestObj], sources: Seq[TestObj]): Seq[TestSeq] = {
  val currentTotal = start.foldLeft(TestObj(0, 0, 0))(_ + _)
  (for (s: TestObj <- sources) yield {
    val newTotal = currentTotal + s
    if (newTotal < target) {
      iterate(start :+ s, sources)
    } else {
      Seq(TestSeq(newTotal, target delta newTotal, (start :+ s).sortBy(e => (e.x, e.y, e.z))))
    }
  }).flatten
}

但我想让这个尾递归。我不能为我的生活找出什么样的模式来做尾递归,同时仍然保持我的for / yield功能..这里的FP向导之一可以指向我正确的方向吗?

更新:感谢下面的评论,我取得了一些进展。我的新测试工具如下所示。但它仍然爆炸..任何优化的提示都是受欢迎的,我很难过......

case class TestObj(x: Int, y: Int, z: Int) {
  def +(that: TestObj): TestObj = {
    new TestObj(this.x + that.x, this.y + that.y, this.z + that.z)
  }

  def <(that: TestObj): Boolean = {
    this.x < that.x && this.y < that.y && this.z < that.z
  }

  def delta(that: TestObj) = {
    math.abs(this.x - that.x) + math.abs(this.y - that.y) + math.abs(this.z - that.z)
  }
}

case class TestSeq(score: TestObj, delta: Int, sequence: Seq[TestObj])

val sources = Seq(
  new TestObj(1, 2, 3), new TestObj(2, 3, 4), new TestObj(3, 4, 5),
  new TestObj(2, 3, 4), new TestObj(3, 4, 5), new TestObj(4, 5, 6),
  new TestObj(3, 4, 5), new TestObj(4, 5, 6), new TestObj(5, 6, 7))
val target = new TestObj(50, 60, 70)

def iterate(start: Seq[TestObj], maxItems: Int, sources: Seq[TestObj]): Set[TestSeq] = {
  val currentTotal = start.foldLeft(TestObj(0, 0, 0))(_ + _)

  if(maxItems == 0) {
    return Set(TestSeq(currentTotal, target delta currentTotal, start.sortBy(f => (f.x,f.y,f.z))))
  }

  sources.flatMap(s => {
    val newTotal = currentTotal + s
    if (newTotal < target) {
      iterate(start :+ s, maxItems - 1, sources)
    } else {
      Set(TestSeq(newTotal, target delta newTotal, start :+ s))
    }
  }).toSet
}

val possibleCombinations = iterate(Seq(new TestObj(0, 0, 0)), 10, sources)
val usableCombinations = possibleCombinations.map(c => TestSeq(c.score, c.delta, c.sequence.drop(1)))

println(usableCombinations)
usableCombinations.toSeq.sortBy(f => f.delta).foreach(uc => {
  println(s"${uc.delta}: ${uc.sequence}")
})

0 个答案:

没有答案
相关问题