0

I'm struggling to achieve a "simple" behaviour: divide pattern matching code in two separate functions.

I'm simplifying the model for clearness purpose:

abstract class Animal
case object Dog extends Animal
case object Cat extends Animal
case object Bird extends Animal
case object Bat extends Animal
case object Dolphin extends Animal

I want to pattern match on these on different functions (because the actual code is pretty long), but there are other arguments so PartialFunctions are giving me the sick...
In a perfect world I could write :

type PF = PartialFunction[(Animal, Int, String), String] 
private def processFlying(a: Animal, n: Int, loc: String): PF = {
  a match {
    case Bird => n + " birds found in " + loc
    case Bat => n + " bats found in " + underground(loc)
  }
}
private def processMarine(a: Animal, n: Int, loc: String): PF = {
  a match {
    case Dolphin => n + " dolphins found in " + submarine(loc)
  }
}
private def processPet(a: Animal, n: Int, loc: String): PF = {
  a match {
    case Dog => n + " dogs found in " + loc
    case Cat => n + " cats found in " + loc
  }
}
def processAnimal(a: Animal, number: Int, location: String) = {
  val processAll = processFlying orElse processMarine orElse processPet
  processAll(a, n, location)
}

However that does not work. Mostly because I need several argument in my functions. "Why U no use tuples?" would you say? Well I tried and the compiler won't stop complaining the expected type is different than actual type, and different to my alias :(

Any help, tips, or alternative ides will be useful!
Cheers


EDIT: I followed Cyrille's answer bu I also need to perform some work before the match, like this:

val processFlying: PF = {
  // doSomething, like declare a sub-function f
  {
      case (b: Bird, n, loc) => f(b)
      case (b: Bat, n, loc) => f(b)
  }
}
Nicolas Cailloux
  • 418
  • 4
  • 13
  • Why does your sub-function need to be inside the `val`? Can it not be, say a `private def` next to it? – Cyrille Corpet Apr 05 '17 at 12:27
  • That's what I did, but I don't need it anywhere else, so.... :) Moreover, I wanted to take advantage of that by using a closure. That's zeal, it seems things are working nice now. But if anyone has a solution, I'm staying aware – Nicolas Cailloux Apr 05 '17 at 15:06

1 Answers1

2

Your problem is that you're mixing method definition and function definition.

def processFlying(a: Animal, n: Int, loc: String): PF

is the signature of a method (of your surrounding object), that takes three arguments and return a PF, ie a PartialFunction[(Animal, Int, String), String].

So, assuming this signature is what you want, you will only be able to get a PartialFunction if you already have an Animal, an Int and a String...

What you more probably want is to define a PF value (without parameters), so more something like

val processFlying: PF = {
  case (Bird, n, loc) => ...
  case (Bat, n, loc) => ...
}

EDIT

To answer your second request (although it is probably overkill, since defining your helper as a private def will do the job), you can alway put the PF block in a closure:

val processFlying = {
  def f = ...
  val res = {
    case (Bird, n, loc) => f(...)
    case (Bat, n, loc) => f(...)
  }
  res
}

However, you have to assign a value to the PartialFunction defining block, otherwise the parser will have trouble knowing what to do with it. That's only because PartialFunction definition with cases block and closures share the {} syntax.

Cyrille Corpet
  • 5,265
  • 1
  • 14
  • 31
  • You're giving me nice clues. I'm starting to figure out how all this works. However, I have a special case (of course): in one of my functions I need to insert code "before the match". I don't know how to insert code in comment so I edited my first message. – Nicolas Cailloux Apr 05 '17 at 10:51