Выражение типа Parser.Parser[Nonterminal] не соответствует Parser.Parser[TypeParameter]
Я возиться с комбинаторами синтаксического анализатора 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))
}
Что меня беспокоит об ошибке, так это то, что а) оба случая typeParam
вернуть TypeParameter
и б) TypeParameter
это реализация Nonterminal
Итак, из того, что я вижу, не должно быть ошибок.
Что здесь происходит и как я могу исправить эту ошибку?
1 ответ
Из-за старшинства дела не такие, как вы думаете. Ваши два случая:
"(" ~> typeDef <~ ")"
а также
identifier ^^ {
case td: TypeDefinition => TypeParameter(Left(td))
case id: Identifier => TypeParameter(Right(id))
}
Так как аниме смайлик относится только к identifier
, тип "(" ~> typeDef <~ ")"
является Parser[TypeDefinition]
не Parser[TypeParameter]
, Так что Скала видит тебя Parser[TypeDefinition]
с Parser[TypeParameter]
и решает, что результат должен быть Parser[NonTerminal]
поскольку это их самый специфический общий суперкласс.
Чтобы это исправить, вы можете просто добавить круглые скобки "(" ~> typeDef <~ ")" | identifier
чтобы сделать приоритет тем, что вы хотели, или применить аниме-смайлик к обоим случаям индивидуально, что также избавляет вас от необходимости сопоставления с образцом:
def typeParam: Parser[TypeParameter] =
"(" ~> typeDef <~ ")" ^^ {
td => TypeParameter(Left(td))
} | identifier ^^ {
id => TypeParameter(Right(id))
}