Scala 2.9:解析器子类不识别;“元素”;推翻

Scala 2.9:解析器子类不识别;“元素”;推翻,scala,parser-combinators,Scala,Parser Combinators,我编写了一个解析器作为词法分析器。这个lexer解析一个文件并返回一个令牌列表,每个令牌都是扩展公共特征的case类或对象 我现在正试图为lexer的输出编写一个解析器,但遇到了一个非常令人困惑的障碍。解析器很乐意隐式地强制转换我的case对象,但是如果我甚至尝试手动调用apply(classHere),解析器就会抛出一个fit 以下是我的代码的简化版本: // CODE trait Token case class StringWrapperIgnoresCase(val string: S

我编写了一个解析器作为词法分析器。这个lexer解析一个文件并返回一个令牌列表,每个令牌都是扩展公共特征的case类或对象

我现在正试图为lexer的输出编写一个解析器,但遇到了一个非常令人困惑的障碍。解析器很乐意隐式地强制转换我的case对象,但是如果我甚至尝试手动调用
apply(classHere)
,解析器就会抛出一个fit

以下是我的代码的简化版本:

// CODE
trait Token

case class StringWrapperIgnoresCase(val string: String) {
  private case class InnerWrapper(s: String)

  lazy val lower = string.toLowerCase

  override lazy val hashCode = InnerWrapper(lower).hashCode

  override def equals(that: Any) =
    that.isInstanceOf[StringWrapperIgnoresCase] &&
      lower == that.asInstanceOf[StringWrapperIgnoresCase].lower
}

case class ID(val text: String)
  extends StringWrapperIgnoresCase(text)
  with Token {
    override def toString = "ID(" + text + ")"
  }

case object PERIOD extends Token

object Parser extends Parsers {
  type Elem = Token

  def doesWork: Parser[Token] = PERIOD

  def doesNotWork: Parser[Token] = ID
}
编译器报告有关
doesnowork
的以下消息:

// ERROR MESSAGE
type mismatch;  found   : alan.parser.ID.type (with underlying type object alan.parser.ID)  required: alan.parser.Parser.Parser[alan.parser.Token]

如何解决此问题?

更新:从您的问题中,我不清楚您到底在问什么,但现在您已经指定需要与答案中的任何
ID
匹配的解析器,下面是一个更惯用的解决方案:

val id: Parser[ID] = accept("ID", { case i: ID => i })
在这里,您提供了解析器所需内容的描述(用于错误消息)和一个以
ID
s作为其域的部分函数。您还可以使用谢菲在对您的答案的评论中提供的
acceptIf
版本


当您引用一个没有参数列表的case类(与case对象相反)时,您会得到自动生成的伴生对象,它不是该类本身的实例。考虑以下事项:

sealed trait Foo
case class Bar(i: Int) extends Foo
case object Baz extends Foo
现在
Baz:Foo
很好,但是
Bar:Foo
将给出一个与您看到的非常类似的错误

还要注意,这里发生的事情并不是严格意义上的铸造。
Parsers
trait有一个具有以下签名的方法:

implicit def accept(e: Elem): Parser[Elem]
当你写这篇文章时:

def doesWork: Parser[Token] = PERIOD
您试图键入一个
Elem
作为
解析器[Elem]
,隐式转换就开始了(有关隐式转换的更多信息,请参阅的第7.3节)。另一方面,当你写这篇文章时:

def doesNotWork: Parser[Token] = ID
您试图将
ID
伴随对象(其类型为
ID.type
,而不是
ID
Token
,因此也不是
Elem
)键入为
解析器[Elem]
,并且没有隐式转换使之成为可能

至少现在,您最好写出
accept(PERIOD)
accept(ID(“任意”))
,并在尝试编译代码时遵守弃用警告:

案例间继承具有潜在的危险bug,这些bug是 不太可能修复


根据TravisBrown和drstevens所说的,我向解析器添加了一个新产品:

def id = {
  acceptIf(
    _ match {
      case ID(_) => true
      case _ => false
    }
  )("'ID(_)' expected but " + _ + " found")
}

def nowWorks = id

我暂时不会接受这个答案,让别人提供比这个更优雅的解决方案。就我的口味而言,这看起来有点混乱,我相信更习惯于函数式编程方法的人会把它变成一行优雅的单行线。

Stevens博士,我还没来得及问你问题,你就删除了你的答案。为什么我不能从case类继承?我必须承认,你链接的线程把我弄糊涂了>
acceptIf(ID.unapply(>.isDefined)(…)
。你应该接受特拉维斯·布朗的回答。它在语言级别指出了代码中的问题,并提出了解决方案。你没有提到你在问题中真正想要的逻辑(在这篇文章中可以看到),也不应该期望其他人成为读心术的人。在看了这篇文章后,你试过了,但没有编译。我可能仍然接受特拉维斯·布朗的回答,但我想我没想到会有人读心术。我说我的解析器正在接受“lexer的输出”,并展示了它返回的两个令牌案例。像Travis那样硬编码ID值意味着解析器只能匹配一个ID!看起来
acceptMatch
比这里的
acceptIf
工作得更好。看一看里面的。它采用分部函数而不是谓词,如果为输入定义分部函数,则返回结果。