Decomposing evaluation in case class

Omid

I got this code from here: It's a very simple expression evaluation

  sealed abstract class Tree
  case class Add(t1: Tree, t2: Tree) extends Tree
  case class Sub(t1: Tree, t2: Tree) extends Tree
  case class Mul(t1: Tree, t2: Tree) extends Tree
  case class Div(t1: Tree, t2: Tree) extends Tree
  case class Num(t: Double) extends Tree

  def eval(t: Tree): Double = t match {
    case Add(t1, t2) => eval(t1)+eval(t2)
    case Sub(t1, t2) => eval(t1)-eval(t2)
    case Mul(t1, t2) => eval(t1)*eval(t2)
    case Div(t1, t2) => eval(t1)/eval(t2)
    case Num(t) => t
  }

How can I decompose eval function into case classes (e.g. Add) so I can have something like: (How Scala compiler do this for Function*, I think these should have same answers)

sealed abstract class Tree{
def eval:???
}
case class Add(t1: Tree, t2: Tree) extends Tree{
  def eval = ???
}
Ben Reich

You could make the abstract Tree class have an eval method that returns a Double:

sealed abstract class Tree {
    def eval: Double
}
case class Add(t1: Tree, t2: Tree) extends Tree {
    def eval = t1.eval + t2.eval
}
case class Sub(t1: Tree, t2: Tree) extends Tree {
    def eval = t1.eval - t2.eval
}
case class Num(t: Double) extends Tree {
    def eval = t
}

And then:

val tree = Add(Num(1), Sub(Num(2), Num(1))) //1+(2-1)
tree.eval //2.0

Another approach is to define a case class for each branching size of the tree:

sealed abstract class Tree {
    def eval: Double
}
case class Tree2(func: (Double, Double) => Double)(d1: Tree, d2: Tree) extends Tree {
    def eval = func(d1.eval, d2.eval)
}
case class Tree1(func: Double => Double)(d1: Tree) extends Tree {
    def eval = func(d1.eval)
}
case class Tree0()(d1: Double) extends Tree {
    def eval = d1
}

Then you can define new tree operations as vals relatively ad-hoc, without defining new classes. This is sometimes preferable:

val Add = Tree2(_ + _) _
val Sub = Tree2(_ - _) _
val Num = Tree0() _

Of course, nothing here is special to Double. You could make Tree generic to parameterize the return type. Here's a small generic version, and an implementation with Strings:

sealed abstract class Tree[T] {
    def eval: T
}
case class Add(t1: Tree[String], t2: Tree[String]) extends Tree[String] {
    def eval = t1.eval + t2.eval
}
case class Sub(t1: Tree[String], t2: Tree[String]) extends Tree[String] {
    def eval = t1.eval.replaceAll(t2.eval, "")
}
case class Str(t: String) extends Tree[String] {
    def eval = t
}

Add(Str("foo"), Sub(Str("barfoobarfoo"), Str("foo"))).eval //"foobarbar"

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related