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.

Original source

Related problems