1

In scala we can use for loops as follows:

for { a <- someCollection
       b = a.someFunc} //inbody we can use b

I need similar functionality with a while loop for example:

while({ val a = someFunction
         a.isDefined        }) { //do something with a in body }

How can I do this in scala?

EDIT

I know we can do this using a var on top and modifying it within the loop but I was looking for something more elegant.

What I wish to accomplish is as follows. The function someFunction iterates over a collection of Options and check for the item that is not a None. If it does not find such an option it returns a None. I can probably do this using

for( a <- myCollection
     if a.isDefined) {} 

but in this case I dont make use of my function.

Sohaib
  • 4,556
  • 8
  • 40
  • 68

3 Answers3

4

You could write your own extended while function, like:

def extendedWhile[T](condFunc: => Option[T])(block: T => Unit): Unit = {
  val a = condFunc
  if (a.isDefined) { 
    block(a.get)
    extendedWhile(condFunc)(block)
  }
}

Which can be used as:

def rand = 
  if ((new scala.util.Random).nextFloat < 0.4) None
  else Some("x")

extendedWhile(rand) {
  x => println(x)
}
// prints out x a random amount of times

This extendedWhile function is tail recursive, so it should normally be as performant as the regular while loop.

Peter Neyens
  • 9,770
  • 27
  • 33
  • 1
    Quite clever. I try to avoid inspecting Options directly so I might define `extendedWhile` as follows: `condFunc.foreach { x => block(x); extendedWhile(condFunc)(block) }` – jwvh Jun 26 '15 at 07:24
  • @jwvh That is indeed a nicer way to define my function. – Peter Neyens Jun 26 '15 at 07:40
  • 2
    @jwvh I agree in general, but in this case tail-recursiveness may be more desirable. – Alexey Romanov Jun 26 '15 at 09:07
  • 1
    Like AlexeyRomanov commented, jwvhs version looks nicer, but it looses the better performance of the tail recursion. – Peter Neyens Jun 26 '15 at 16:36
  • @PeterNeyens How does the usage for it work. I mean in the usage part how is `x=>println(x)` is assigned to block. – Sohaib Jul 01 '15 at 07:01
  • @Sohaib In my example is `x => println(x)` the definition of the `block: T => Unit` parameter. – Peter Neyens Jul 01 '15 at 07:02
  • @PeterNeyens I have checked that it works but I was thinking it should be something like `extendedWhile(rand) ({ x => println(x) })`. Is this some sort of syntactic sugar? – Sohaib Jul 01 '15 at 07:08
  • You can change parentheses to brackets in [some cases](http://stackoverflow.com/a/4387118/5020846). – Peter Neyens Jul 01 '15 at 07:41
0

I am not sure I like this, but one way to do this is to define the variable as 'var' outside the loop.

var a: Boolean = _;
def someFunction: Boolean = true
while({ a = someFunction; a }) {
    println("hi " + a)
}
marios
  • 8,874
  • 3
  • 38
  • 62
  • 1
    I forgot to mention in the question I already did that but it looks not so 'likeable' as you mentioned. – Sohaib Jun 26 '15 at 05:32
  • I know, it doesn't. I feel that the closure of the while loop predicate doesn't expand inside the body of the while loop, so I am not sure there is a good way to do this without writing your own while loop or using macros. – marios Jun 26 '15 at 05:39
0

For is actually syntactic sugar for foreach, map, and flatMap.

So your code above desugars to:

someCollection.map { a=> f(a)}.foreach {b => ... //something using b}

Now, while is not a desugaring, but an actual imperative syntactic construct.

So the best you can do is

var a = true
while (a) {
  a = someFunction (a)
}

In practice I never find myself using while, and instead use higher-order functions: like

input.takeWhile(_ != '').foreach { //do something }
triggerNZ
  • 4,221
  • 3
  • 28
  • 34