2016-04-05 12 views
0

Ich bin mit Scala Parser Kombinatoren rumalbern, und ich bin ratlos durch einen Fehler, den ich nicht ganz zu verstehen scheinen.Ausdruck des Typs Parser.Parser [Nonterminal] entspricht nicht Parser.Parser [TypeParameter]

Hier ist der entsprechende Code:

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)) 
    } 

Was mich über den Fehler nervt ist, dass a) die beiden Fälle von typeParam Rückkehr ein TypeParameter, und b) TypeParameter ist eine Implementierung von Nonterminal, so von dem, was ich kann Sehen Sie, es sollte kein Fehler erzeugt werden.

Was passiert hier und wie behebe ich diesen Fehler?

Antwort

1

Aufgrund der Priorität sind die Fälle nicht das, was Sie denken, sie sind. Ihre beiden Fälle sind:

"(" ~> typeDef <~ ")" 

und

identifier ^^ { 
    case td: TypeDefinition => TypeParameter(Left(td)) 
    case id: Identifier => TypeParameter(Right(id)) 
} 

So, da der Anime Smiley nur identifier gilt, die Art der "(" ~> typeDef <~ ")" ist Parser[TypeDefinition], nicht Parser[TypeParameter]. Scala sieht also, dass du eine Parser[TypeDefinition] mit einer Parser[TypeParameter] ORingest und beschließt, dass das Ergebnis eine Parser[NonTerminal] sein muss, da dies ihre spezifischste gemeinsame Oberklasse ist.

dies zu beheben Sie Klammern um "(" ~> typeDef <~ ")" | identifier nur hinzufügen können, um den Vorrang, was Sie es den Anime Smiley auf beide Fälle einzeln sein soll oder nur insoweit Anwendung, erspart Ihnen auch Mustererkennung aus mit:

def typeParam: Parser[TypeParameter] = 
    "(" ~> typeDef <~ ")" ^^ { 
    td => TypeParameter(Left(td)) 
    } | identifier ^^ { 
    id => TypeParameter(Right(id)) 
    } 
+0

Ich hätte erkennen sollen, dass du die Kombinatoren kombinieren kannst. –