Scala: pattern matching with reusable condition

advertisements

Considering this case of pattern matching:

foo match {
    case x if expensiveCalculation(x).nonEmpty => // do something with expensiveCalculation(x)
...
}

is it possible to "label" or reuse the expensiveCalculation(x) after the =>?

Ideally I was expecting something like:

foo match {
        case x val ec = expensiveCalculation(x); if ec.nonEmpty => // do something with ec
    ...
    }


You can write an extractor for the type of x (here assuming InputType):

object Expensive {
  def unapply(x: InputType): Option[OutputType] = expensiveCalculation(x)
}

Now, you can use it in your pattern matching:

fooList match {
  case _ :: Expensive(output) :: _ => ...
  case _ :: x :: _ => ...
}

However, this is a cumbersome way to do what you want, if you do this for many calculations (you need to define an extractor every time).

You might do it once and for all by defining the following:

case class Comput[-A, +B](f: A => Option[B]) {
  def unapply(a: A): Option[B] = f(a)
}

Now, you can use it as follow:

val intString = "10"
val IntOf = Comput[String, Int](s => Try(s.toInt).toOption)

intString match {
  case IntOf(x) => x
  case other => 0
} // returns 10: Int

However, you cannot dispense from defining IntOf before using it in pattern matching (the compiler parser seems to be lost).