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.
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.
Finally, we discovered that a for-comprehension is just syntactic sugar for a sequence of calls to methods foreach, map, flatMap, and withFilter.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With