评估Scala中的表达式

时间:2014-10-28 16:51:41

标签: scala case-class

我对scala有点新意,我在这里有一个程序可以完成我想要的一切,除了一件我似乎无法弄清楚的事情。我有表达式,我基于一些简单的数学规则简化表达式。然后我提示用户绑定变量并用用户键入的整数替换变量,然后计算表达式。这一切都像我想要的那样。但是,当我不将特定变量替换为整数时,我仍然想要简化/评估表达式。我只是简单地评估表达式而不要求用户输入x的值,我删除了在我的环境中替换x的语句。问题是当eval方法在我的表达式中遇到x时调用env时,我得到一个scala.Match错误。为了更清楚我想要做的是用我的例子中的表达式。表达式:(x +(x *(y - (z / 2))))只用2代替变量y和z,我希望看到的结果是(x + x)。我将不胜感激任何建议/帮助!我的程序在这一点看起来像这样:

var n1 = 0
var n2 = 0
var n3 = 0

type Environment = String => Int

lazy val exp: Tree = Sum(Var("x"), Times(Var("x"), Minus(Var("y"), Divide(Var("z"), Const(2)))))


lazy val env: Environment = {
  case "x" => n1          //take this line out to not bind x
  case "y" => n2
  case "z" => n3
}

abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " + " + r + ")"
}
case class Minus(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " - " + r + ")"
}
case class Times(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " * " + r + ")"
}
case class Divide(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " / " + r + ")"
}
case class Var(n: String) extends Tree {
  override def toString = n
}
case class Const(v: Int) extends Tree {
  override def toString = v.toString
}

def simplify(t: Tree): Tree = t match {
  case Times(Const(1), r)     => simplify(r)
  case Times(l, Const(1))     => simplify(l)
  case Times(Const(0), r)     => Const(0)
  case Times(l, Const(0))     => Const(0)
  case Sum(Const(0), r)       => simplify(r)
  case Sum(l, Const(0))       => simplify(l)
  case Minus(l, Const(0))     => simplify(l)
  case Minus(l, r) if l == r  => Const(0)
  case Divide(Const(0), r)    => Const(0)
  case Divide(l, Const(1))    => simplify(l)
  case Divide(l, r) if l == r => Const(1)
  case Times(l, r)            => Times(simplify(l), simplify(r))
  case Sum(l, r)              => Sum(simplify(l), simplify(r))
  case Minus(l, r)            => Minus(simplify(l), simplify(r))
  case Divide(l, r)           => Divide(simplify(l), simplify(r))
  case _                      => t
}

def eval(t: Tree): Int = t match {
  case Sum(l, r)    => eval(l) + eval(r)
  case Minus(l, r)  => eval(l) - eval(r)
  case Times(l, r)  => eval(l) * eval(r)
  case Divide(l, r) => eval(l) / eval(r)
  case Var(n)       => env(n)
  case Const(v)     => v
}

println("Expression: " + exp)
println("Simplified: " + simplify(exp))
println("Enter the binding for x.")         //take this line out to not bind x
n1 = readInt()                              //take this line out to not bind x
println("Enter the binding for y.")
n2 = readInt()
println("Enter the binding for z.")
n3 = readInt()
println("Evaluation: " + eval(exp))

2 个答案:

答案 0 :(得分:1)

我稍微改变了你的代码,让它按你的意愿工作:

abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " + " + r + ")"
}
case class Minus(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " - " + r + ")"
}
case class Times(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " * " + r + ")"
}
case class Divide(l: Tree, r: Tree) extends Tree {
  override def toString = "(" + l + " / " + r + ")"
}
case class Var(n: String) extends Tree {
  override def toString = n
}
case class Const(v: Int) extends Tree {
  override def toString = v.toString
}

object ExprEval {
  lazy val exp: Tree = Sum(Var("x"), Times(Var("x"), Minus(Var("y"), Divide(Var("z"), Const(2)))))
  var env = Map[String, Int]()

  def simplify(t: Tree, recursive : Boolean = true): Tree = {
    t match {
      case Sum(Const(0), r)           => simplify(r)
      case Sum(l, Const(0))           => simplify(l)
      case Sum(Const(l), Const(r))    => Const(l + r)
      case Sum(Var(l), Var(r)) if l == r => Times(Const(2), Var(l))
      case Sum(l, r) if recursive     => simplify(Sum(simplify(l), simplify(r)), recursive = false)

      case Minus(l, Const(0))         => simplify(l)
      case Minus(l, r) if l == r      => Const(0)
      case Minus(Const(l), Const(r))  => Const(l - r)
      case Minus(l, r) if recursive   => simplify(Minus(simplify(l), simplify(r)), recursive = false)

      case Times(Const(1), r)         => simplify(r)
      case Times(l, Const(1))         => simplify(l)
      case Times(Const(0), r)         => Const(0)
      case Times(l, Const(0))         => Const(0)
      case Times(Const(l), Const(r))  => Const(l * r)
      case Times(l, r) if recursive   => simplify(Times(simplify(l), simplify(r)), recursive = false)

      case Divide(Const(0), r)        => Const(0)
      case Divide(l, Const(1))        => simplify(l)
      case Divide(l, r) if l == r     => Const(1)
      case Divide(Const(l), Const(r)) => Const(l / r)
      case Divide(l, r) if recursive  => simplify(Divide(simplify(l), simplify(r)), recursive = false)

      case Var(n)                     => env.get(n).map(Const).getOrElse(Var(n))
      case _                          => t
    }
  }

  def eval(t: Tree): Int = t match {
    case Sum(l, r)    => eval(l) + eval(r)
    case Minus(l, r)  => eval(l) - eval(r)
    case Times(l, r)  => eval(l) * eval(r)
    case Divide(l, r) => eval(l) / eval(r)
    case Var(n)       => env(n)
    case Const(v)     => v
  }

  def main(args: Array[String]) {
    env = Map()
    println(s"env: $env, exp : $exp, simplified : ${simplify(exp)}")

    env = Map("y" -> 2, "z" -> 2)
    println(s"env: $env, exp : $exp, simplified : ${simplify(exp)}")

    env = Map("z" -> 4)
    println(s"env: $env, exp : $exp, simplified : ${simplify(exp)}")

    env = Map("x" -> 3, "y" -> 2, "z" -> 2)
    println(s"env: $env, exp : $exp, simplified : ${simplify(exp)}")
  }
}

如果没有绑定变量,则返回简化的原始表达式树。如果绑定了所有变量,它将产生与eval()相同的结果。

输出:

env: Map(), exp : (x + (x * (y - (z / 2)))), simplified : (x + (x * (y - (z / 2))))
env: Map(y -> 2, z -> 2), exp : (x + (x * (y - (z / 2)))), simplified : (2 * x)
env: Map(z -> 4), exp : (x + (x * (y - (z / 2)))), simplified : (x + (x * (y - 2)))
env: Map(x -> 3, y -> 2, z -> 2), exp : (x + (x * (y - (z / 2)))), simplified : 6

答案 1 :(得分:1)

这是一个相对干净的解决方案。我只包括了我修改的部分。

type Environment = String => Option[Int]

lazy val env: Environment = {
  case "y" => Some(n2)
  case "z" => Some(n3)
  case _ => None
}

def simplify(t: Tree): Tree = {
  val reducedTree = t match {
    case Times(l, r)  => Times(simplify(l), simplify(r))
    case Sum(l, r)    => Sum(simplify(l), simplify(r))
    case Minus(l, r)  => Minus(simplify(l), simplify(r))
    case Divide(l, r) => Divide(simplify(l), simplify(r))
    case Var(n)       => env(n).map(Const).getOrElse(t)
    case _            => t
  }

  reducedTree match {
    case Times(Const(1), r)         => r
    case Times(l, Const(1))         => l
    case Times(Const(0), r)         => Const(0)
    case Times(l, Const(0))         => Const(0)
    case Times(Const(l), Const(r))  => Const(l * r)
    case Sum(Const(0), r)           => r
    case Sum(l, Const(0))           => l
    case Sum(Const(l), Const(r))    => Const(l + r)
    case Minus(l, Const(0))         => l
    case Minus(l, r) if l == r      => Const(0)
    case Minus(Const(l), Const(r))  => Const(l - r)
    case Divide(Const(0), r)        => Const(0)
    case Divide(l, Const(1))        => l
    case Divide(l, r) if l == r     => Const(1)
    case Divide(Const(l), Const(r)) => Const(l / r)
    case _                          => reducedTree
  }
}