def compute(i: Int): (Int, () => Boolean) =
(i - 1) -> { () => i > 1 }
To create an immutable while you'll need iteration - a function that accepts state and returns new state of same type plus exit condition.
Iterator.continually
It's not the best solution - in my opinion this code is hard to read, but since you mentioned it:
val (r, p) = Iterator.continually(()).
scanLeft( 13 -> { () => true } ){
case ((r, p), _) => compute(r)
}.dropWhile{ case (r, p) => p() }.
next
// r: Int = 0
// p: () => Boolean = <function0>
You could use val (r, _) = since you don't need p.
If you want a solution with Iterator see this answer with Iterator.iterate.
Tail recursion
I guess this is an idiomatic solution. You could always rewrite your while loop as tail recursion with explicit state type:
@annotation.tailrec
def lastWhile[T](current: T)(f: T => (T, () => Boolean)): T = {
val (r, p) = f(current)
if (p()) lastWhile(r)(f)
else r
}
lastWhile(13){ compute }
// Int = 0
Scalaz unfold
In case you are using scalaz there is such method already. It produces a Stream, so you should get the last element.
At the end of an iteration you should produce an Option (None is an exit condition) with Pair of stream element (r) and next state (r, p()):
unfold(13 -> true) { case (r0, p0) =>
val (r, p) = compute(r0)
p0.option(r -> (r, p()))
}.last
// Int = 0
p. Do you meando {...} while(p())?