Regex не подходит для понимания, если защита не компилируется

Почему это не будет компилироваться

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

Но удаление if

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

или переупорядочить порядок двух списков в понимании

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

компилирует?

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

Ответ 1

Вы можете увидеть переведенное для понимания с помощью этой команды:

scalac -Xprint:all <file>.scala

В первом примере результирующий код выглядит следующим образом (я немного очистил вывод):

List.empty[String]
  .flatMap(((s) =>
    List.empty[scala.util.matching.Regex]
      .map(regex => {
        private[this] val x$2 =
        s match {
          case ([email protected](([email protected]_))) => 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(([email protected]_), regex(([email protected]_))) => ss.$eq$eq("foo")
    })).map(((x$4) => x$4 match {
      case scala.Tuple2(([email protected]_), regex(([email protected]_))) => s
    })))
  )

Проблема заключается в том, что предложение withFilter использует выражение regex(ss) непосредственно в инструкции case, но значение regex там не определено. Я не уверен, что это можно считать недостатком в спецификации языка или в компиляторе. Сообщение об ошибке, безусловно, не очень полезно.

Вы можете прочитать подробности в главе 6.19 Scala спецификация языка.

Ответ 2

Это может вам помочь.

 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
  }