6

我想创建一个特殊的计算器。我认为这case class对运营来说是个好主意:

sealed class Expr
case class add(op1:Int, op2:Int) extends Expr
case class sub(op1:Int, op2:Int) extends Expr
case class mul(op1:Int, op2:Int) extends Expr
case class div(op1:Int, op2:Int) extends Expr
case class sqrt(op:Int) extends Expr
case class neg(op:Int) extends Expr
/* ... */

现在我可以使用 match-case 来解析输入。也许,我也应该使用traits(即:trait Distributivitytrait Commutativity),这可能吗?这是一个好主意吗?

4

1 回答 1

13

在开始添加附加价值不那么明确的特征之前,您应该掌握正确的基础知识。您现在这样做的方式使这些类不是很有用,至少在构建经典 AST(或“解析树”)时不是。想象一下 4 * (3+5)。在您可以使用乘法运算之前,您必须评估先加法。这使事情变得复杂。您通常想要的是“一次”编写公式的能力,例如 Mul(4,Add(3, 5))。但是那样做是行不通的,因为您不能将 Ints 或 Doubles 放入您自己的类层次结构中。通常的解决方案是数字的包装类,比如“Num”。然后我们有:Mul(Num(4),Add(Num(3),Num(5))。这可能看起来很复杂,但现在你“一下子”有了,你可以做一些事情,比如引入常量和变量,简化(例如 Mul(Num(1),x) --> x),推导...

为了得到这个,你需要一些类似的东西

sealed trait Expr {
  def eval:Int      
}
case class Num(n:Int) extends Expr {
  def eval = n
}
case class Neg(e: Expr) extends Expr {
  def eval = - e.eval() 
}
case class Add(e1: Expr, e2: Expr) extends Expr {
  def eval = e1.eval + e2.eval  
}
...

现在您可以编写一个解析器,将“4*(3+5)”转换为 Mul(Num(4),Add(Num(3),Num(5)),并通过对该表达式调用 eval 获得结果。

Scala 已经包含一个称为解析器组合器的解析库。有关接近上述代码的示例,请参见http://jim-mcbeath.blogspot.com/2008/09/scala-parser-combinators.html

于 2010-09-03T11:59:23.443 回答