Built-in way to simulate a while loop without side effects
functional-programming, scala
Solution
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
Problem
Generally the boilerplate of while loop looks like(`r` is the result I want, `p` is the predictor: ``` var r, p; while(p()) { (r, p) = compute(r) } ``` I can convert it into a recursion to get rid of `var`: ``` def f(r) = { val (nr, p) = compute(r) if(p()) nr else f(nr) } ``` Is there a built-in way to implement such logic? I knew `Iterator.continually`, but it seems still to take a `var` to store side effect.