Search code examples
scalafor-comprehension

Scala for-comprehension 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 decompose tuples in the for comprehension.

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)

fails 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 doesn't this last example work? What is the difference?


Solution

  • This is a bug:

    SI-5589: For-comprehension on Either.RightProjection with Tuple2 extractor in generator fails to compile

    withFilter() is called (some documentation references filter(), but that was changed in 2.8), which messes with the type inference.

    withFilter() is used for things like for(a <- b if c), though according to the 6.19 it shouldn't be used in this case.

    This latter bug is captured in SI-1336: spec requires type checking of for-comprehension to consider refutability, which has been open for seven years (2008).

    Perhaps some future generation will find the fix.


    See why does filter have to be defined for pattern matching in a for loop in scala?