案例类和特征

时间:2010-09-03 08:47:28

标签: scala traits case-class

我想创建一个特殊的计算器。我认为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等等,这是可行的吗?这是个好主意吗?

1 个答案:

答案 0 :(得分:13)

在开始添加不那么清晰的附加值的特征之前,您应该掌握正确的基础知识。你现在这样做的方式使这些类不是很有用,至少在构建经典AST(或“解析树”)时不是这样。想象一下4 *(3 + 5)。在使用乘法运算之前,必须首先评估加法。这让事情变得复杂。你通常想要的是能够“立刻”写下你的公式,例如: Mul(4,Add(3,5))。但是这不会那样,因为你不能将Ints或Doubles放入你自己的类层次结构中。通常的解决方案是Numbers的包装类,比如说“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包含一个名为parser combinators的解析库。有关接近上述代码的示例,请参阅http://jim-mcbeath.blogspot.com/2008/09/scala-parser-combinators.html