考虑以下案例类层次结构,用于模拟无上下文语法规则。
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特征。
如何指定?
答案 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时。
单个课程有时不可能延长特质,有时也不可能。您可以拥有单独的班级Conc
和ConcBNF
,同样适用于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