Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using case class to display Expressions

I am trying to achieve the example shown in Martin Odersky's CourseRa Scala course to try and display expressions holding Sums/Prods using appropriate brackets. I came up with the below solution:

package expressions

trait Expr {
    def eval : Int = {
      this match {
        case Number(n) => n
        case Sum(e1,e2) => e1.eval + e2.eval
      }
    }
    //def show( exp : Expr) : String
}

case class Number(n:Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr
case class Prod(e1 : Expr, e2 : Expr) extends Expr
case class Var(x:Char) extends Expr

object testExpr {
  def show(exp : Expr) : String = {
    exp match {
      case Number(x) => x.toString()
      case Sum(e1, e2) => show(e1) + "+" + show(e2)
      case Prod(e1,e2) => 
        val st1 = e1 match {
          case Sum(a,b) => "(" + show(Sum(a,b)) + ")"
          case _ => show(e1)
        }
        val st2 = e2 match {
          case Sum(a,b) => "(" + show(Sum(a,b)) + ")"
          case _ => show(e2)
        }
        st1 + "*" + st2
      case Var(x) => x.toString
    }
  }
}

object test extends App{

  println(testExpr.show(Sum(Number(1),Number(2))))
  println(Sum(Number(1),Number(3)).eval)
  println(testExpr.show(Sum(Number(2),Prod(Number(10),Var('x')))))

  println(testExpr.show(Sum(Prod(Number(2),Var('x')),Var('y'))))
  println(testExpr.show(Prod(Sum(Number(2),Var('x')),Var('y'))))
  println(testExpr.show(Prod(Sum(Number(2),Var('x')),Sum(Number(3),Var('y')))))
}

The way I am deciding on putting the brackets is definitely not the best solution. Can anyone suggest a better solution to achieve the same.

Thanks and Regards, Paromita

like image 556
ParoTech Avatar asked Nov 09 '13 06:11

ParoTech


3 Answers

Somewhat similar to ParoTech's and Val's, only slightly DRYer:

def show(e: Expr): String = {

  def paren(e:Expr) = {
    e match {
      case Sum(_, _) => "(" + show(e) + ")"
      case _ => show(e)
    }
  }

  e match {
    case Number(n) => n.toString
    case Var(s) => s
    case Sum(e1, e2) => show(e1) + " + " + show(e2)
    case Prod(e1, e2) => paren(e1) + " * " + paren(e2)
  }

}
like image 67
dev Avatar answered Sep 21 '22 18:09

dev


you were pretty close actually. the code i've come up with is as follows:

case Variable(name) => name

case Product(e1, e2) => "%s * %s".format(
  e1 match {
    case Sum(_, _) => "(%s)".format(show(e1))
    case _ => show(e1)
  },
  e2 match {
    case Sum(_, _) => "(%s)".format(show(e2))
    case _ => show(e2)
  }
)

which would be further rewritten using tuple matching as

case Product(e1, e2) =>
  val format = (e1, e2) match {
    case (Sum(_, _), _) => "(%s) * %s"
    case (_, Sum(_, _)) => "%s * (%s)"
    case (_, _) => "%s * %s"
  }
  format.format(show(e1), show(e2))
like image 43
Dennis Krupenik Avatar answered Sep 24 '22 18:09

Dennis Krupenik


I guess that supposed solution is to prefix

   case Prod(l, r) => show(l) + "*" + show(r)

with

   case Prod(Sum(sl, sr), r) => "(" + show(sl) + " + " + show(sr) + ")" + "*" + show(r)

as demonstrated here https://github.com/glebd/scala-course/blob/master/workspace/hello-project/src/week4/exprs.sc

The resulting code is

  def show(e: Expr): String = e match {
      case Number(n) => n.toString
      case Var(v) => v
      case Prod(Sum(e1, e2), Sum(e3, e4)) => "(" + show(e1) + "+" + show(e2) + ")*(" + show(e3) + "+" + show(e4) + ")"
      case Prod(Sum(e1, e2), e3) => "(" + show(e1) + "+" + show(e2) + ")*" + show(e3)
      case Prod(e1, Sum(e2, e3)) => show(e1) + "*(" + show(e2) + "+" + show(e3) + ")"
      case Sum(e1, e2) => show(e1) + "+" + show(e2)
      case Prod(e1, e2) => show(e1) + "*" + show(e2)
  } 

I have no idea what Krupennik's solution is supposed to do. Oderski did not demonstrate constructions like that. But this solution sheds some light on what Krupennik is doing.

like image 34
Val Avatar answered Sep 24 '22 18:09

Val