Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's for-comprehension `if` statements

Tags:

scala

Is it possible in scala to specialize on the conditions inside an if within a for comprehension? I'm thinking along the lines of:

val collection: SomeGenericCollection[Int] = ...  trait CollectionFilter case object Even extends CollectionFilter case object Odd extends CollectionFilter  val evenColl = for { i <- collection if(Even) } yield i //evenColl would be a SomeGenericEvenCollection instance  val oddColl = for { i <- collection if(Odd) } yield i //oddColl would be a SomeGenericOddCollection instance 

The gist is that by yielding i, I get a new collection of a potentially different type (hence me referring to it as "specialization")- as opposed to just a filtered-down version of the same GenericCollection type.

The reason I ask is that I saw something that I couldn't figure out (an example can be found on line 33 of this ScalaQuery example. What it does is create a query for a database (i.e. SELECT ... FROM ... WHERE ...), where I would have expected it to iterate over the results of said query.

like image 426
Dylan Avatar asked Oct 31 '11 03:10

Dylan


People also ask

How Scala for comprehension works?

Scala offers a lightweight notation for expressing sequence comprehensions. Comprehensions have the form for (enumerators) yield e , where enumerators refers to a semicolon-separated list of enumerators. An enumerator is either a generator which introduces new variables, or it is a filter.

What operations is a for comprehension syntactic sugar for?

Finally, we discovered that a for-comprehension is just syntactic sugar for a sequence of calls to methods foreach, map, flatMap, and withFilter.

What is a for comprehension in Scala?

Comprehensions is a construct in Scala which allows us to evaluate certain expressions. The For Comprehension has the form for (enumerators) yield e , where enumerators refer to a semi-colon separated list of enumerators. An enumerator can either be a generator that iterates the list or a filter.

What is the use of yield keyword in Scala for comprehension?

yield keyword will returns a result after completing of loop iterations. The for loop used buffer internally to store iterated result and when finishing all iterations it yields the ultimate result from that buffer.


1 Answers

So, I think you are asking if it is possible for the if statement in a for-comprehension to change the result type. The answer is "yes, but...".

First, understand how for-comprehensions are expanded. There are questions here on Stack Overflow discussing it, and there are parameters you can pass to the compiler so it will show you what's going on.

Anyway, this code:

val evenColl = for { i <- collection if(Even) } yield i 

Is translated as:

val evenColl = collection.withFilter(i => Even).map(i => i) 

So, if the withFilter method changes the collection type, it will do what you want -- in this simple case. On more complex cases, that alone won't work:

for {   x <- xs   y <- ys   if cond } yield (x, y) 

is translated as

xs.flatMap(ys.withFilter(y => cond).map(y => (x, y))) 

In which case flatMap is deciding what type will be returned. If it takes the cue from what result was returned, then it can work.

Now, on Scala Collections, withFilter doesn't change the type of the collection. You could write your own classes that would do that, however.

like image 177
Daniel C. Sobral Avatar answered Sep 20 '22 14:09

Daniel C. Sobral