title: Making a scala function tail-recursive when using yield?
body: <p>I've got a function that's working;</p>
  
  <pre><code>def iterate(start: Seq[TestObj], sources: Seq[TestObj]): Seq[TestSeq] = {
    val currentTotal = start.foldLeft(TestObj(0, 0, 0))(_ + _)
    (for (s: TestObj &lt;- sources) yield {
      val newTotal = currentTotal + s
      if (newTotal &lt; target) {
        iterate(start :+ s, sources)
      } else {
        Seq(TestSeq(newTotal, target delta newTotal, (start :+ s).sortBy(e =&gt; (e.x, e.y, e.z))))
      }
    }).flatten
  }
  </code></pre>
  
  <p>But I'd like to make this tail-recursive. I can not for the life of me figure out what the pattern is to do tail recursion while still maintaining my for/yield functionality.. Can one of the FP wizards around here point me in the right direction?</p>
  
  <p><strong>UPDATE:</strong> Thanks to the comments below, I've made some headway. My new test harness looks like the below. But it still bombs out.. Any hints to optimize are welcome, I'm pretty stumped..</p>
  
  <pre><code>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 &lt;(that: TestObj): Boolean = {
      this.x &lt; that.x &amp;&amp; this.y &lt; that.y &amp;&amp; this.z &lt; 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 =&gt; (f.x,f.y,f.z))))
    }
  
    sources.flatMap(s =&gt; {
      val newTotal = currentTotal + s
      if (newTotal &lt; 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 =&gt; TestSeq(c.score, c.delta, c.sequence.drop(1)))
  
  println(usableCombinations)
  usableCombinations.toSeq.sortBy(f =&gt; f.delta).foreach(uc =&gt; {
    println(s"${uc.delta}: ${uc.sequence}")
  })
  </code></pre>