Suppose I have a set of case classes that represent constants, variables, and unary and binary operations on them, similar to one from "Case Classes and Pattern Matching" chapter in Programming in Scala:
abstract class Value {
def basicEvaluate(varArray: Array[Double]): Double
def evaluate(varArray: Array[Double]) = basicEvaluate(varArray)
}
case class Constant(d: Double) extends Value {
override def basicEvaluate(varArray: Array[Double]) = d
}
case class Variable(i: Int) extends Value {
override def basicEvaluate(varArray: Array[Double]) = varArray(i)
}
case class Add(v1: Value, v2: Value) extends Value {
override def basicEvaluate(varArray: Array[Double]) = v1.evaluate(varArray) + v2.evaluate(varArray)
}
...
Then, suppose I have some means to produce expression trees that reuse certain subexpressions many times, and I wish to be able to evaluate the expression efficiently, so that each distinct subexpression gets evaluated only once. For this reason, I introduce a trait
trait UsingCache extends Value {
var cached: Option[Double] = None
override def evaluate(varArray: Array[Double]) = {
if (cached == None) {
cached = Some(basicEvaluate(varArray))
}
cached.get
}
}
Then, I can do the following:
val expr = new Variable(0) with UsingCache
val expr2 = new Add(expr, expr) with UsingCache
expr2.evaluate(Array(5.0))
and it works.
My question is - how to implement a function def extend(value: Value): UsingCache
which would recursively replace each Value
in the tree with a corresponding .. with UsingCache
object? I wish to keep this logic decoupled from the individual subclasses of Value
(e.g., when I add a new operation, it shouldn't contain any code specific for caching). Is there some way to do this using implicit conversion? Or some ideas how to use Scala reflection (I'm using Scala 2.12)?
Aucun commentaire:
Enregistrer un commentaire