DAML and Haskell users are used to writing irrefutable patterns on the left of <-
in a do
block, such as to destructure a tuple. However, if you write the same in Scala,
for {
(a, b) <- Some((1, 2))
} yield a + b
it will desugar like so:
Some((1, 2))
.withFilter(check$ifrefutable$1 => check$ifrefutable$1: @unchecked match {
case ((a @ _), (b @ _)) => true
case _ => false
})
.map(x$1 => x$1: @unchecked match {
case ((a @ _), (b @ _)) => a + b
})
No annotations either
As with case
, there are no type annotations to the left of <-
, only type patterns:
for {x: Int <- List(1, 2)} yield x
// desugars to
List(1, 2)
.withFilter(check$ifrefutable$1 => check$ifrefutable$1: @unchecked match {
case (x @ (_: Int)) => true
case _ => false
})
.map(x: Int => x)
Fixing the pattern
The fix for destructuring is to separate the destructuring from the <-
binding:
for {
ab <- Some((1, 2))
(a, b) = ab
} yield a + b
which desugars like so:
Some((1, 2))
.map { ab =>
val x$2 = ab: @unchecked match {
case (x$1 @ ((a @ _), (b @ _))) => (x$1, a, b)
}
val x$1 = x$2._1
val a = x$2._2
val b = x$2._3
(ab, x$1)
}
.map(x$3 => x$3: @unchecked match {
case ((ab @ _), ((a @ _), (b @ _))) => a + b
})
It’s longer, but it works with types that can’t be filtered, and for those that can, at least it won’t silently drop if your pattern turned out to be not-so-irrefutable.
Fixing the annotation
For type annotations, the fix is to use an ascription on the expression instead:
for {x <- List(1, 2): List[Int]} yield x
Seeing how something desugars
If you are curious how any expression desugars in Scala, you can use reify
in the REPL:
scala> import reflect.runtime.universe.reify
import reflect.runtime.universe.reify
scala> reify { for {x <- List(1, 2): List[Int]} yield x }
res11: reflect.runtime.universe.Expr[List[Int]] = Expr[List[Int]]((List.apply(1, 2): `package`.List[Int]).map(((x) => x))(List.canBuildFrom))
scala> reify { 2 :: Nil }
res12: reflect.runtime.universe.Expr[List[Int]] =
Expr[List[Int]]({
<synthetic> <artifact> val x$1 = 2;
Nil.$colon$colon(x$1)
})
Note that the output is a printed syntax tree rather than valid Scala code; nevertheless it is a good way to figure out what some piece of higher-level syntax will do in Scala.
Tested with Scala 2.12.11.