Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining two match patterns in one

Tags:

scala

How does one combine (in a nice way) two Scala match'es?

First I have to test if an Option is a valid value:

myOption match {
  case Some(op) =>
    doSomethingWith(op)
  case None =>
    handleTheError()

Then if op was valid, I want to test for another pattern:

Path(request.path) match {
  case "work" => {
    println("--Let's work--")

  }
  case "holiday" => {
    println("--Let's relax--")
  }
  case _ => {
    println("--Let's drink--")
  }
}

I could combine them like this:

myOption match {
  case Some(op) =>
    doSomethingWith(op)
    Path(request.path) match {
      case "work" => {
        println("--Let's work--")          
      }
      case "holiday" => {
        println("--Let's relax--")
      }
      case _ => {
        println("--Let's drink--")
      }
    }
  case None =>
    handleTheError()

But, it feels sloppy. Is there a better way to combine them in some way or another.

Update

Apologies, I should have explained better. I'm actually trying to find out if there is a known pattern for simplifying (or factoring out) these control structures. For example (imagine this was true):

x match {
 case a => {
   y match {
    case c => {}
    case d => {}
   }
 }
 case b => {}
}

equals

x -> y match {
  case a -> c => {}
  case a -> d => {}
  case b => {}
}

I was just wandering if someone has already identified some refactoring patterns for control flow, much like algebra where 2(x + y) = 2x + 2y

like image 584
Jack Avatar asked Feb 29 '12 14:02

Jack


2 Answers

You can do

myOption map { success } getOrElse handleTheError

or with scalaz,

myOption.cata(success, handleTheError)

where success is something like

def success(op: Whatever) = {
  doSomethingWith(op)
  Path(request.path) match {
    case "work"    => println("--Let's work--")
    case "holiday" => println("--Let's relax--")
    case _         => println("--Let's drink--")      
  }
}

Update

Your pseudocode

x -> y match {
  case a -> c => {}
  case a -> d => {}
  case b => {}
}

can be literally translated to scala as

(x, y) match {
  case (a, c) => {}
  case (a, d) => {}
  case (b, _) => {}
}

It looks nice (and that's probably what you wanted) if inner matcher have only few options (c and d in this case), but it leads to code duplication (repeating of pattern a). So, in general I'd prefer map {} getOrElse {}, or separation of pattern-matchers on smaller functions. But I repeat, in your case it looks reasonable.

like image 134
4e6 Avatar answered Nov 12 '22 23:11

4e6


If the scrutinees (the expressions on which you match) do not depend on each other, i.e. you can compute them independently, you could perform both matches at the same time by wrapping the scrutinees in a tuple.

So your example:

x match {
 case a => {
   y match {
    case c => fooC(...)
    case d => fooD(...)
   }
 }
 case b => fooB(...)
}

could be rewritten as:

(x,y) match {
  case (a, c) => fooC(...)
  case (a, d) => fooD(...)
  case (b, _) => fooB(...)
}

...as long as y doesn't depend on x.

like image 27
Philippe Avatar answered Nov 13 '22 00:11

Philippe