david.perez david.perez - 1 month ago 6
Scala Question

Extractors in for vs extractors in assignment

I have this doubt with extractors.

If I can do this:

val a :: b = List(1, 2, 3)


why I cannot do this:

val c = for ( a :: b <- List(1, 2, 3) } yield a

Answer

The translation of a for-yield expression in Scala (without using guards) is the map function. If you try and use map instead, it'll seem a little clear as to the quirk with the code:

List(1, 2, 3).map((x: Int) => ???)

When you map over a List[+A], you project each value, one at a time. You don't have the entire list at your disposable inside the higher order function.

On the contrary, when using pattern matching on the list itself, the compiler will translate your first example into (after some cleanup):

def main(args: Array[String]): Unit = {
  private[this] val x$1: (Int, List[Int]) = List(1, 2, 3) match {
    case (head: Int, tl: List[Int])scala.collection.immutable.::[Int]((a @ _), (b @ _)) => Tuple2[Int, List[Int]](a, b)
  };

  val a: Int = x$1._1;
  val b: List[Int] = x$1._2;
  ()

Which is a pattern match on the List[Int], matching the case of a head and tail. It's simply syntatic sugar for regular pattern matching, same as for-yield is syntatic sugar for a map. They simply do different things.