Scala for understanding with tuple decomposition

for { a <- Some(1) b <- Some(2) } yield (a, b) 

returns Some((1, 2))

 for { a <- Right(1).right b <- Left(2).left } yield (a, b) 

returns Left((1, 2))


Now I want to expand the tuples in understanding.

 for { (a, b) <- Some((1, 2)) (c, d) <- Some((3, 4)) } yield (a, b, c, d) 

returns Some((1, 2, 3, 4))

 for { (a, b) <- Right((1, 2)).right (c, d) <- Left((3, 4)).left } yield (a, b, c, d) 

unable to compile:

 error: constructor cannot be instantiated to expected type; found : (T1, T2) required: scala.util.Either[Nothing,(Int, Int)] (a, b) <- Right((1, 2)).right error: constructor cannot be instantiated to expected type; found : (T1, T2) required: scala.util.Either[(Int, Int),Nothing] 

Why is this last example not working? What is the difference?

+6
source share
3 answers

This is mistake:

SI-5589: for understanding by Either.RightProjection with a Tuple2 extractor in the generator cannot compile

withFilter() (some links to filter() documentation, but this was changed in 2.8), which contradicts the type of output.

withFilter() used for things like for(a <- b if c) , although in accordance with 6.19 it should not be used in this case.

This last mistake was recorded in SI-1336: spec requires a type check for understanding in order to consider the issue of rebuttal , which was open for seven years (2008).

Perhaps some future generation will find a fix.


See why should a filter be defined to match patterns in a for loop in scala?

+3
source

Since the generators for (Any, Any) <- Or are not "incontrovertible", filters are added to the desugared code ( why should a filter be defined to match patterns in a for loop in scala? ), Resulting in:

 Right((1, 2)).right.filter { case (a, b) => true; case _ => false }.flatMap({ case(a, b) => Left((3, 4)).left.filter { case (c, d) => true; case _ => false }.map({case (c, d) => (a, b, c, d) }) }) 

There is a compilation error in the filters, because the filter method for Right looks like this (left looks like):

 def filter[X](p: B => Boolean): Option[Either[X, B]] = e match { case Left(_) => None case Right(b) => if(p(b)) Some(Right(b)) else None } 

This means that the compiler is trying to do the following:

 (T1, T2) match { case Left(_) => None case Right(b) => if(p(b)) Some(Right(b)) else None } 

Which fails because (T1, T2) cannot be entered in either [A, B] (which goes straight on), where A is Nothing and B is (Int, Int).

You can get something close to this using:

 for { a <- Right((1, 2)).right b <- Left((3, 4)).left } yield (a, b) match { case ((c, d), (e, f)) => (c, d, e, f) case _ => } 
+4
source

This may be a restriction on expressions. Embodiment

 for { (a, b) <- Some((1, 2)) (c, d) <- Some((3, 4)) } yield (a, b, c, d) 

in

 Some((1, 2)).flatMap({case(a, b) => Some((3, 4)).map({case (c, d) => (a, b, c, d) }) }) 

works in both directions. With the expression Either , only the map / flatMap version works.

 for { (a, b) <- Right((1, 2)).right (c, d) <- Left((3, 4)).left } yield (a, b, c, d) Right((1, 2)).right.flatMap({ case(a, b) => Left((3, 4)).left.map({case (c, d) => (a, b, c, d) }) }) 

I do not recommend using Either , use \/ from scalaz instead. http://eed3si9n.com/learning-scalaz/Either.html Either not the left or right side, which is a problem because it does not indicate where the error or value is.

+3
source

All Articles