Scala:使用特征扩展案例类层次结构的子集

时间:2014-08-08 19:11:19

标签: scala mixins traits case-class

考虑以下案例类层次结构,用于模拟无上下文语法规则。

case class Rule(head: Nonterminal, body: Expression)

trait BNF

sealed abstract class Expression

// Bracketed expression.
abstract class BracketedExpr(expr: Expression) extends Expression

case class Group(expr: Expression) extends BracketedExpr(expr)
case class Plus(expr: Expression) extends BracketedExpr(expr)
case class Opt(expr: Expression) extends BracketedExpr(expr)
case class Star(expr: Expression) extends BracketedExpr(expr)

// Concatenated.
case class Conc(list: List[Expression]) extends Expression

// Alternated.
case class Alt(list: List[Expression]) extends Expression

// Base expression.
abstract class Literal extends Expression with BNF

case class Nonterminal(value: String) extends Literal 
case class Terminal(value: String) extends Literal
case class Regex(value: String) extends Literal
case class Epsilon() extends Literal
case class EndOfInputSymbol() extends Literal

def fancyFunction(expr: Expression with BNF): ???

现在我想指定一个Conc(atenation)和Alt(ernate)具有特征BNF当且仅当list中的所有表达式都具有特征BNF时。 这样,我想检查方法调用是否所有子层次结构中的表达式都具有BNF特征。

如何指定?

2 个答案:

答案 0 :(得分:0)

应该在编译时知道类型,但是您可以执行运行时检查以查看返回的对象是否基于特定特征。

基于您的类的简单示例:

/** your classes here */

case class NullExpr() extends Expression

scala> def derive(l:List[Expression]) = l.fold(Epsilon()) {
     | (acc, elem) => if (!acc.isInstanceOf[BNF] || !elem.isInstanceOf[BNF]) 
     | NullExpr() else elem }
derive: (l: List[Expression])Expression

scala> derive(List(Epsilon(), Regex("abcd")))
res8: Expression = Regex(abcd)

scala> res8.isInstanceOf[BNF]
res9: Boolean = true

scala> derive(List(NullExpr(), Epsilon()))
res10: Expression = NullExpr()

scala> res10.isInstanceOf[BNF]
res11: Boolean = false

答案 1 :(得分:0)

  

现在我想指定一个Conc(atenation)和Alt(ernate)具有特征BNF当且仅当列表中的所有表达式都具有特征BNF时。

单个课程有时不可能延长特质,有时也不可能。您可以拥有单独的班级ConcConcBNF,同样适用于Alt。相反,我只是做

sealed abstract class Expression {
  def isBNF: Boolean
}

abstract class Literal extends Expression {
  def isBNF = true
}

case class Conc(list: List[Expression]) extends Expression {
  def isBNF = list.all(_.isBNF) // or val isBNF if you want to avoid recalculation
}

// and so on