Выражение типа 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))
  }
Другие вопросы по тегам