我正在搞乱Scala的解析器组合器,而且我很难理解我似乎并不理解的错误。
以下是相关代码:
trait ASTNode
trait Terminal extends ASTNode
trait Nonterminal extends ASTNode
case class Identifier(id: String) extends Terminal
case class TypeDefinition(identifier: Identifier, optionalType: Option[TypeParameters]) extends Nonterminal
case class TypeParameters(params: List[TypeParameter]) extends Nonterminal
case class TypeParameter(typeDef: Either[TypeDefinition, Identifier]) extends Nonterminal
object Parser extends RegexParsers {
def identifier: Parser[Identifier] = """([a-zA-Z_][\w'-]*)""".r ^^ Identifier
def typeDef: Parser[TypeDefinition] = identifier ~ opt("of" ~> typeParams) ^^ {
case id ~ optional => TypeDefinition(id, optional)
}
// the bit causing the error
def typeParam: Parser[TypeParameter] = "(" ~> typeDef <~ ")" | identifier ^^ {
case td: TypeDefinition => TypeParameter(Left(td))
case id: Identifier => TypeParameter(Right(id))
}
有什么问题让我烦恼,那就是a)typeParam
两个案例都返回TypeParameter
,而b)TypeParameter
是Nonterminal
的实现因此,从我所看到的,不应该产生任何错误。
此处发生了什么以及如何解决此错误?
答案 0 :(得分:1)
由于优先权,案件并不是您认为的。你的两个案例是:
"(" ~> typeDef <~ ")"
和
identifier ^^ {
case td: TypeDefinition => TypeParameter(Left(td))
case id: Identifier => TypeParameter(Right(id))
}
因为动画笑脸仅适用于identifier
,"(" ~> typeDef <~ ")"
的类型为Parser[TypeDefinition]
,而不是Parser[TypeParameter]
。因此,Scala看到您正在Parser[TypeDefinition]
与Parser[TypeParameter]
进行ORing,并确定结果必须是Parser[NonTerminal]
,因为它是最具体的常见超类。
要解决此问题,您只需在"(" ~> typeDef <~ ")" | identifier
周围添加括号即可使其优先于您的预期,或者将动画笑脸分别应用于两种情况,这也可以避免您进行模式匹配:
def typeParam: Parser[TypeParameter] =
"(" ~> typeDef <~ ")" ^^ {
td => TypeParameter(Left(td))
} | identifier ^^ {
id => TypeParameter(Right(id))
}