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)
}
}
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 case
s block and closures share the {}
syntax.