2016-05-11 10 views
0

Ich habe die folgenden Fallklassen. Ausdrücke sind mathematische Operationen und Zahlen. Zum Beispiel ist add eine Unterklasse von expression und rekursiv enthält es zwei Felder, die num sind, was auch Unterklasse von expression ist.Hinzufügen von Feldern von Fallklassen in Scala

abstract class Expression 
    case class num (num: Int) extends Expression 
    case class add (left: Expression, right: Expression) extends Expression 

    abstract class Result 
    case class numericResult (v : Int) extends Result 

Es gibt andere Arten von Return als auch, damit ich nicht Fallklassen

Evaluate-Methode soll Ausdruck nehmen entfernen kann, unbox es dann die Operation durchführt und ein Ergebnis zurück, die Kästen im Ergebnis sind Klasse

def evaluate(expr: Expression) : Result = { 
    expr match { 
     case num(n) => new numericResult(n) 
     case add(l, r) => new numericResult(evaluate(l).v + evaluate(r).v) //add will never be called on imaginary numbers 
     case addi(l, r) => new imaginaryResult(...) //adds imaginary numbers 

    } 
} 

Aber wenn ich versuche, es zu bewerten, ich erhalte eine Fehlermeldung:

error: value v is not a member of Result 

Wie kann ich sicherstellen, dass Scala weiß, dass l und r vom Typ num sind, und wenn sie ausgewertet werden, gibt es numericResult statt Result? Ich kann annehmen, dass, wenn add evaluate (l) und evaluate (r) numericResut zurückgibt, aber l und r auch verschachtelte Adds sein könnten.

+0

Warum nicht dann wieder 'numericResult' von' evaluate'? – Tair

+0

def auswerten (expr: Ausdruck): numericResult = ... – Tair

+0

Es gibt andere Typen, die auswerten können –

Antwort

0

Hier ist die Variante, die Ihr Auswertungsergebnis im laufenden Betrieb überprüft:

def evaluate(expr: Expression) : Result = { 
    expr match { 
     case num(n) => new numericResult(n) 
     case add(l, r) => (evaluate(l), evaluate(r)) match { 
      case (numericResult(l), numericResult(r)) => new numericResult(l + r) 
      case (x, y) => throw new IllegalStateException(s"Numeric Results expected, got $x, $y") 
     } 
     case addi(l, r) => new imaginaryResult(...) //adds imaginary numbers 
    } 
} 

Um jedoch Typsicherheit in der Kompilierung zu erhalten, müssen Sie Expression Typ mit dependent types, sagen wir, erwartete Ergebnis Art betrachten beglückwünschend der Bewertung.

1

Parametrierung der Expression s durch die Art der Result, die sie produzieren:

abstract class Expression[T <: Result] 
case class num (num: Int) extends Expression[numericResult] 
case class add (left: Expression[numericResult], right: Expression[numericResult]) extends Expression[numericResult] 
case class addi (left: Expression[Result], right: Expression[Result]) extends Expression[imaginaryResult] 

abstract class Result 
// why lower-case? 
case class numericResult (v : Int) extends Result 
case class imaginaryResult(v: Int) extends Result 

def evaluate [T <: Result](expr: Expression[T]) : T = { 
    expr match { 
    case num(n) => new numericResult(n) 
    case add(l, r) => new numericResult(evaluate(l).v + evaluate(r).v) //add will never be called on imaginary numbers 
    case addi(l, r) => new imaginaryResult(???) //adds imaginary numbers 
    } 
}