【问题标题】:Foiled by path-dependent types被路径依赖类型挫败
【发布时间】:2012-09-19 01:22:11
【问题描述】:

在一个 trait 中,我在使用从另一个 trait 中的方法返回的 Parser 时遇到问题。编译器抱怨类型不匹配,在我看来问题是由于路径相关的类。我不知道如何得到我想要的。

trait Outerparser extends RegexParsers {

  def inner: Innerparser

  def quoted[T](something: Parser[T]) = "\"" ~> something <~ "\""
  def quotedNumber = quoted(inner.number)     // Compile error
  def quotedLocalNumber = quoted(number)      // Compiles just fine
  def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}

}

trait Innerparser extends RegexParsers {

  def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}

}

还有错误:

[error] /Path/to/MyParser.scala:6: type mismatch
[error]  found   : minerals.Innerparser#Parser[Int]
[error]  required: Outerparser.this.Parser[?]
[error]   def quotedNumber = quoted(inner.number)

我有点明白了:每个“某事”方法都定义了一个 Parser 类型,其路径特定于封闭类(Outerparser 或 Innerparser)。 Outerparser 的“引用”方法需要一个 Outerparser.this.Parser 类型的实例,但正在获取 Innerparser#Parser。

我希望能够使用从此类或其他类获得的解析器引用。我该怎么做?

【问题讨论】:

    标签: scala parser-combinators path-dependent-type


    【解决方案1】:

    无论好坏,您通常使用 Scala 解析器组合库的方式是将所有内容包装在一个封闭的 trait 或对象中,extendsRegexParsers 这样的 trait。我不太清楚为什么 API 是这样设计的。

    但是,无论如何,一旦它们都属于RegexParsers 的同一个实例,它们都会看到相同的Parser 类型:

    trait Everything extends RegexParsers {
        trait Outerparser {
            ...
        }
    
        trait Innerparser {
            ...
        }
    }
    

    每个人都很开心。


    不要把所有东西都放在同一个范围内;将其视为解析器组合器 API 导入名称的怪异方式,即,您可以很容易地做到这一点

    import scala.util.parsing.combinator._
    import scala.util.parsing.input._
    
    object blah extends RegexParsers
    import blah._
    
    trait Outerparser {
        ...
    }
    
    trait Innerparser {
        ...
    }
    

    【讨论】:

    • 我不想把我所有的解析代码都放在同一个范围内。还有其他想法吗?
    【解决方案2】:

    您可以使用自类型注释使其编译,同时仍保持模块化:

    trait OuterParser extends RegexParsers { this: InnerParser =>
      def quoted[T](something: Parser[T]) = "\"" ~> something <~ "\""
      def quotedNumber = quoted(number)     // Compile error
    }
    
    trait InnerParser extends RegexParsers {
      def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
    }
    
    object MyCompleteParser extends OuterParser with InnerParser
    

    self-type 注释基本上说 OuterParser 依赖于 InnerParser(它们必须混合在一起才能创建一个适当的可实例化类)。编译器因此确定在 OuterParser 和 InnerParser 中,Parser 指的是同一个类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-06
      • 2013-04-17
      • 2011-03-20
      • 2019-01-27
      相关资源
      最近更新 更多