Search code examples
scalafunctional-programmingpattern-matchingfor-comprehensionpartialfunction

inexplicable for-comprehension result in Scala


I understand for-expression is translated into map and flatMap. But I found something that I can not explain and need your helps. Here are two toy examples:

for {
    None <- List(Option(1),None)
} yield 0

//res0: List[Int] = List(0, 0)

Q1: Why Some(1) is map to 0 ? I was expecting List(0),

update1:
thanks the comment of @marios , ths one is more bizarre.
for(None <- List(Some(1), None) ) yield None returns List(Some(1), None).

update2:
some says it is a variable, but in IDE, it really links to a None object.


I use IntelliJ to auto-translate the above for-expression to map-expression:

List(Option(1), None).map { case None => 0 }  

//scala.MatchError: Some(1) 

Q2: The error from this map-expression is expected, while the for-expression in first question doesn't give me this error. Why they get the different computation ?


Solution

  • This appears to be a bug in the Scala compiler. The Scala Language Specification states: "In a first step, every generator p <- e, where p is not irrefutable for the type of e is replaced by p <- e.withFilter { case p => true; case _ => false }", and then "a for comprehension for (p <- e) yield e′ is translated to e.map { case p => e′ }."

    This means your example, for { None <- List(Option(1), None) } yield 0, should be translated to

    List(Option(1),None).withFilter { case None => true; case _ => false }.map{case None => 0}
    

    which evaluates to List(0), as you expected.