Scala extending while loops to do-until expressions
scala
Solution
With a minor modification you can turn your current approach in a kind of mini fluent API, which results in a syntax that is close to what you want:
class run[A](body: => A) {
def until(cond: A => Boolean): A = {
val result = body
if (cond(result)) result else until(cond)
}
}
object run {
def apply[A](body: => A) = new run(body)
}
Since `do` is a reserved word, we have to go with `run`. The result would now look like this:
run {
// body with a result type A
} until (a => ...)
Edit:
I just realized that I almost reinvented what was already proposed in the linked question. One possibility to extend that approach to return a type `A` instead of `Unit` would be:
def repeat[A](body: => A) = new {
def until(condition: A => Boolean): A = {
var a = body
while (!condition(a)) { a = body }
a
}
}
Problem
I'm trying to do some experiment with Scala. I'd like to repeat this experiment (randomized) until the expected result comes out and get that result. If I do this with either while or do-while loop, then I need to write (suppose 'body' represents the experiment and 'cond' indicates if it's expected): ``` do { val result = body } while(!cond(result)) ``` It does not work, however, since the last condition cannot refer to local variables from the loop body. We need to modify this control abstraction a little bit like this: ``` def repeat[A](body: => A)(cond: A => Boolean): A = { val result = body if (cond(result)) result else repeat(body)(cond) } ``` It works somehow but is not perfect for me since I need to call this method by passing two parameters, e.g.: ``` val result = repeat(body)(a => ...) ``` I'm wondering whether there is a more efficient and natural way to do this so that it looks more like a built-in structure: ``` val result = do { body } until (a => ...) ``` One excellent solution for body without a return value is found in this post: How Does One Make Scala Control Abstraction in Repeat Until?, the last one-liner answer. Its `body` part in that answer does not return a value, so the `until` can be a method of the new `AnyRef` object, but that trick does not apply here, since we want to return `A` rather than `AnyRef`. Is there any way to achieve this? Thanks.