Friday, August 4, 2017

Regex unapply in for comprehension with if guard not compiling

Leave a Comment

Why is that the following will not compile

for {     s <- List.empty[String]     regex <- List.empty[scala.util.matching.Regex]     regex(ss) = s     if ss == "foo" } yield s 

But removing the if

for {     s <- List.empty[String]     regex <- List.empty[scala.util.matching.Regex]     regex(ss) = s } yield s 

or rearranging the order of the two lists in the for comprehension

for {     regex <- List.empty[scala.util.matching.Regex]     s <- List.empty[String]     regex(ss) = s     if ss == "foo" } yield s 

compiles?

Scalafiddle: http://scalafiddle.net/console/2519ff98d434cb522589f54a9c5fcf55

2 Answers

Answers 1

You can see the translated for-comprehension using this command:

scalac -Xprint:all <file>.scala 

In your first example the resulting code looks like this (I cleaned up the output a bit):

List.empty[String]   .flatMap(((s) =>     List.empty[scala.util.matching.Regex]       .map(regex => {         private[this] val x$2 =         s match {           case (x$1@regex((ss@_))) => scala.Tuple2(x$1, ss)         };         val x$1 = x$2._1;         val ss = x$2._2;         scala.Tuple2(regex, x$1)       }).withFilter((x$3 => x$3 match {       case scala.Tuple2((regex@_), regex((ss@_))) => ss.$eq$eq("foo")     })).map(((x$4) => x$4 match {       case scala.Tuple2((regex@_), regex((ss@_))) => s     })))   ) 

The problem seems to be that the withFilter clause uses the expression regex(ss) directly in the case statement, but the value regex it is not defined there. I'm not sure if this can be considered a flaw in the language specification, or in the compiler. The error message is certainly not very helpful.

You can read up on the details in chapter 6.19 of the Scala language specification.

Answers 2

This might help you.

 import scala.util.matching.Regex  import scala.util.control.Exception._    for {     s <- List.empty[String]     regex <- List.empty[scala.util.matching.Regex]     ss <- extract(regex, s)     if ss == "foo"   } yield s    def extract(regex: Regex, s: String): Option[String] = allCatch.opt {     val regex(ss) = s     ss   } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment