2012-10-03 14 views
8

Ho una classe caso come il seguente:Scala duck typing pattern matching

// parent class 
sealed abstract class Exp() 

// the case classes I want to match have compatible constructors 
case class A (a : Exp, b : Exp) extends Exp 
case class B (a : Exp, b : Exp) extends Exp 
case class C (a : Exp, b : Exp) extends Exp 

// there are other case classes extending Exp that have incompatible constructor, e.g. 
//  case class D (a : Exp) extends Exp 
//  case class E() extends Exp 
// I don't want to match them 

voglio abbinare:

var n : Exp = ... 
n match { 
    ... 
    case e @ A (a, b) => 
     foo(e, a) 
     foo(e, b) 
    case e @ B (a, b) => 
     foo(e, a) 
     foo(e, b) 
    case e @ C (a, b) => 
     foo(e, a) 
     foo(e, b) 
    ... 
} 

def foo(e : Exp, abc : Exp) { ... } 

c'è un modo per unire che tre casi in un solo caso (senza aggiungere una classe genitore intermedia ad A, B, C)? Non riesco a cambiare la definizione di A, B, C o Exp. Una sorta di:

var n : Exp = ... 
n match { 
    ... 
    case e @ (A | B | C) (a, b) => // invalid syntax 
     foo(e, a) 
     foo(e, b) 
    ... 
} 

che ovviamente non funziona, e non fare:

var n : Exp = ... 
n match { 
    ... 
    case e @ (A (a, b) | B (a, b) | C (a, b)) => // type error 
     foo(e, a) 
     foo(e, b) 
    ... 
} 

risposta

11

Mentre la "soluzione" che segue è in realtà solo un modo diverso di scrivere ciò che già avete, potrebbe aiutare se è necessario utilizzare lo stesso match in più di un luogo e si desidera evitare la duplicazione del codice.

Il seguente personalizzato unapply:

object ExpABC { 
    def unapply(e:Exp):Option[(Int, Int)] = e match { 
     case A(a, b) => Some(a, b) 
     case B(a, b) => Some(a, b) 
     case C(a, b) => Some(a, b) 
     case _ => None 
    } 
} 

consente di scrivere

n match { 
    case e @ ExpABC(a, b) => 
     println(e) 
     println(a) 
     println(b) 
} 

In questo modo non è necessario modificare le classi originali a tutti. Non sono a conoscenza di un modo migliore per fare ciò che non comporta la modifica delle classi A/B/C, ma sono impaziente di imparare @ Stackoverflow;)