This page is no longer maintained — Please continue to the home page at www.scala-lang.org

while comprehensions ?

4 replies
Maxime Lévesque
Joined: 2009-08-18,
User offline. Last seen 42 years 45 weeks ago.

 Can comprehensions be created with a while ?
ex :
    var i = 0;
    var res = while(i < 10) yield i;

    for(x <- res) println(x);
0
1
2
3
...

 This example doesn't seem particularly usefull, because the for
comprehension would be just as short, but I have a case where
 i want to enumerate based on a contition.

Thanks
David Flemström
Joined: 2009-08-10,
User offline. Last seen 42 years 45 weeks ago.
Re: while comprehensions ?
p, li { white-space: pre-wrap; }On Saturday 22 August 2009 23:01:12 Maxime Lévesque wrote:
> Can comprehensions be created with a while ?
> ex :
> var i = 0;
> var res = while(i < 10) yield i;
>
> for(x <- res) println(x);
> 0
> 1
> 2
> 3
> ...
>
> This example doesn't seem particularly usefull, because the for
> comprehension would be just as short, but I have a case where
> i want to enumerate based on a contition.
>
> Thanks
In the above example, how should the compiler know that it has to increase i each time? It doesn't make any sense to me.


If you want to have values in a range, do the following:


val i = 10
val res = 0 until i
for(x <- res) println(x) //or: res.foreach(println)
>0
>1
>2
>3
> ...
>9


If you instead say:
val res = 0 to 10 //note: to
...the range will include 10 too.


David Flemström
david.flemstrom@gmail.com
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: while comprehensions ?
Not really. It would be better if you asked about how to solve your particular problem. I only saw "while" used once in Scala, aside "while(true)" statements with Actors.

2009/8/22 Maxime Lévesque <maxime.levesque@gmail.com>

 Can comprehensions be created with a while ?
ex :
    var i = 0;
    var res = while(i < 10) yield i;

    for(x <- res) println(x);
0
1
2
3
...

 This example doesn't seem particularly usefull, because the for
comprehension would be just as short, but I have a case where
 i want to enumerate based on a contition.

Thanks



--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.
ichoran
Joined: 2009-08-14,
User offline. Last seen 2 years 3 weeks ago.
Re: while comprehensions ?
While-comprehensions aren't built in, probably because they don't make much sense in general.

But if you want something specific with the sort of functionality you have suggested here, I can think of two reasonable options:

(1) Extend Iterable/Iterator to take a Unit => Boolean that it calls every time in place of Iterator's hasNext; then create one of these in a for loop like normal (i.e. basically copy the strategy that Range takes, except as an unbounded rather than bounded collection).  If you want it to give index numbers, have next return the index.

(2) Write a custom class that does what you want.  The naming here may be somewhat inadvisable (it is generally bad form to distinguish classes and reserved words by capitalization only), but, as an example:

class While(val condition : Int=>Boolean) {
  def apply[T](result : Int=>T) : Seq[T] = {
    var i = 0
    var L : List[T] = Nil
    while (condition(i)) { L = result(i) :: L ; i+=1 }
    L.reverse
  }
}

object While {
  def apply(condition : Int => Boolean) = new While(condition)
}

and you could then use this like so:

> While(i=>i*i < 10) (i => i*i*i)
res0: Seq[Int] = List(0, 1, 8, 27)

> While(_<5) (_+1)
res1 : Seq[Int] = List(1, 2, 3, 4, 5)

> var more = true
more: Boolean = true

> While (_=>more) (_=> { print("Stop (y/n)? ") ; val yn = System.in.read.toChar ; println(yn) ; more = (yn!='y')) ; yn })
Stop (y/n)? n
Stop (y/n)? 7
Stop (y/n)? Y
Stop (y/n)? y
res2: Seq[Char] = List(n, 7, Y, y)

The syntax is *slightly* uglier than a pure for/while construct since you need to pass functions and that can't always be done invisibly (e.g. the _=> is required in the last example).  But it works pretty well if what you really want is a way to accumulate a list until a value goes false, and you need a count of iterations on the way.

(Keep in mind you need to re-set "more" to true each time you call that While loop--it's left at false on exit.  Strategy (1) is better if you want to use the full set of map, foreach, for, etc..; strategy (2) lets you get exactly what you want without an extra "map" keyword.)

  --Rex


2009/8/22 Maxime Lévesque <maxime.levesque@gmail.com>

 Can comprehensions be created with a while ?
ex :
    var i = 0;
    var res = while(i < 10) yield i;

    for(x <- res) println(x);
0
1
2
3
...

 This example doesn't seem particularly usefull, because the for
comprehension would be just as short, but I have a case where
 i want to enumerate based on a contition.

Thanks

David Flemström
Joined: 2009-08-10,
User offline. Last seen 42 years 45 weeks ago.
Re: while comprehensions ?
p, li { white-space: pre-wrap; }It's also pretty easy to introduce the "conventional" for construct like the one in Java, but with additional "yield"-like functionality, which might give more control:


def oldfor[R](init: => Unit, cond: => Boolean, action: => Unit)(body: => R):
Seq[R] = {
import scala.collection.mutable.ArrayBuffer
val buffer = new ArrayBuffer[R]


init
while(cond) {
buffer += body
action
}
buffer.toSequence
}


//Usage:
var i = 0
oldfor(i = 1, i < 20, i += 2) {
println(i)
} //prints 1, 3, 5 ... 19
val ints = oldfor(i = 3, i < 30, i += 3) (i)
>ints: Seq[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27)


On Sunday 23 August 2009 03:49:05 Rex Kerr wrote:
> While-comprehensions aren't built in, probably because they don't make much
> sense in general.
>
> But if you want something specific with the sort of functionality you have
> suggested here, I can think of two reasonable options:
>
> (1) Extend Iterable/Iterator to take a Unit => Boolean that it calls every
> time in place of Iterator's hasNext; then create one of these in a for loop
> like normal (i.e. basically copy the strategy that Range takes, except as
> an unbounded rather than bounded collection). If you want it to give index
> numbers, have next return the index.
>
> (2) Write a custom class that does what you want. The naming here may be
> somewhat inadvisable (it is generally bad form to distinguish classes and
> reserved words by capitalization only), but, as an example:
>
> class While(val condition : Int=>Boolean) {
> def apply[T](result : Int=>T) : Seq[T] = {
> var i = 0
> var L : List[T] = Nil
> while (condition(i)) { L = result(i) :: L ; i+=1 }
> L.reverse
> }
> }
>
> object While {
> def apply(condition : Int => Boolean) = new While(condition)
> }
>
> and you could then use this like so:
> > While(i=>i*i < 10) (i => i*i*i)
>
> res0: Seq[Int] = List(0, 1, 8, 27)
>
> > While(_<5) (_+1)
>
> res1 : Seq[Int] = List(1, 2, 3, 4, 5)
>
> > var more = true
>
> more: Boolean = true
>
> > While (_=>more) (_=> { print("Stop (y/n)? ") ; val yn =
>
> System.in.read.toChar ; println(yn) ; more = (yn!='y')) ; yn })
> Stop (y/n)? n
> Stop (y/n)? 7
> Stop (y/n)? Y
> Stop (y/n)? y
> res2: Seq[Char] = List(n, 7, Y, y)
>
> The syntax is *slightly* uglier than a pure for/while construct since you
> need to pass functions and that can't always be done invisibly (e.g. the
> _=> is required in the last example). But it works pretty well if what you
> really want is a way to accumulate a list until a value goes false, and you
> need a count of iterations on the way.
>
> (Keep in mind you need to re-set "more" to true each time you call that
> While loop--it's left at false on exit. Strategy (1) is better if you want
> to use the full set of map, foreach, for, etc..; strategy (2) lets you get
> exactly what you want without an extra "map" keyword.)
>
> --Rex
>
>
> 2009/8/22 Maxime Lévesque <maxime.levesque@gmail.com>
>
> > Can comprehensions be created with a while ?
> > ex :
> > var i = 0;
> > var res = while(i < 10) yield i;
> >
> > for(x <- res) println(x);
> > 0
> > 1
> > 2
> > 3
> > ...
> >
> > This example doesn't seem particularly usefull, because the for
> > comprehension would be just as short, but I have a case where
> > i want to enumerate based on a contition.
> >
> > Thanks


David Flemström
david.flemstrom@gmail.com

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland