Why can't this Scala for expressions using tuples be compiled?

With Scala 2.8.1, compiling this:

val t = (40, 2) println(for ((i, j) <- List(t)) yield i + j) val e: Either[String, (Int, Int)] = Right(t) println(e.right.map { case (i, j) => i + j }) println(for ((i, j) <- e.right) yield i + j) 

gives the following:

 test.scala:9: error: constructor cannot be instantiated to expected type; found : (T1, T2) required: Either[Nothing,(Int, Int)] println(for ((i, j) <- e.right) yield i + j) 

According to the Program in Scala, the for statement should be equivalent to the map / case statement, but only the latter compiles. What am I doing wrong, and how do I do this?

+7
source share
2 answers

Actually, this is not exactly the translation that is happening. You can refer to this answer for more complete guidance, but this case is not explicitly mentioned even there.

What happens is that to understand the pattern matching, a case is used that does not match the match. For example,

 for((i, j) <- List((1, 2), 3)) yield (i, j) 

will return List((1, 2)): List[(Any, Any)] , since withFilter is called first. Now Either does not seem to have withFilter , so it will use filter , and here is the actual translation of this for understanding:

 e.right.filter { case (i, j) => true; case _ => false }.map { case (i, j) => i + j } 

This gives exactly the same error. The problem is that e.right returns RightProjection , but filter on RightProjection[A, B] returns Option[Either[Nothing, B]] .

The reason for this is that there is no such thing as an β€œempty” Either (or RightProjection ), so it must encapsulate its result on Option .

Having said all this, it is really amazing when you look at the level of understanding. I think the right thing would be for filter to return some sort of filtered projection.

+11
source

The right option you might expect is not returned right, but RightProjection. This fix is:

 println(for ((i, j) <- e.right.toOption) yield i + j) 
+2
source

All Articles