简体   繁体   English

由路径依赖类型挫败

[英]Foiled by path-dependent types

I'm having trouble using, in one trait, a Parser returned from a method in another trait. 我在一个特性中使用了一个Parser从另一个特征中的方法返回时遇到了麻烦。 The compiler complains of a type mismatch and it appears to me that the problem is due to the path-dependent class. 编译器抱怨类型不匹配,在我看来问题是由路径依赖类引起的。 I'm not sure how to get what I want. 我不知道如何得到我想要的东西。

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}

}

And the error: 而错误:

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

I sort-of get the idea: each "something" method is defining a Parser type whose path is specific to the enclosing class (Outerparser or Innerparser). 我得到了一个想法:每个“东西”方法定义一个Parser类型,其路径特定于封闭类(Outerparser或Innerparser)。 The "quoted" method of Outerparser expects an an instance of type Outerparser.this.Parser but is getting Innerparser#Parser. Outerparser的“引用”方法需要一个类型为Outerparser.this.Parser的实例,但正在获取Innerparser#Parser。

I like to be able to use quoted with a parser obtained from this class or some other class. 我希望能够使用从此类或其他类获得的解析器引用。 How can I do that? 我怎样才能做到这一点?

For better or for worse, the way you usually use the Scala parser combinator libraries is to wrap everything in an enclosing trait or object that extends a trait like RegexParsers . 为了更好或更坏,您通常使用Scala的解析器组合库的方法是在一个封闭的特征或对象来包装的一切extends像一个特点RegexParsers I'm not quite sure why the API was designed like this. 我不太清楚为什么API是这样设计的。

But, anyway, once they all belong to the same instance of RegexParsers , they all see the same Parser type: 但是,无论如何,一旦它们都属于同一个RegexParsers实例,它们都会看到相同的Parser类型:

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

    trait Innerparser {
        ...
    }
}

And everyone is happy. 每个人都很开心。


Don't think of it as putting everything in the same scope; 不要认为它把所有东西放在同一范围内; think of it as the parser-combinator API's kooky way of importing names, ie, you could just as easily do 把它想象成解析器 - 组合器API导入名称的怪异方式,也就是说,你可以轻松地做到

import scala.util.parsing.combinator._
import scala.util.parsing.input._

object blah extends RegexParsers
import blah._

trait Outerparser {
    ...
}

trait Innerparser {
    ...
}

You can use a self-type annotation to make it compile while still preserving the modularity: 您可以使用自我类型注释使其进行编译,同时仍保留模块性:

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

The self-type annotation basically says that OuterParser depends InnerParser (they must be mixed together to create a proper instantiatable class). 自我类型注释基本上说OuterParser依赖于InnerParser(它们必须混合在一起才能创建一个适当的可实例化类)。 The compiler thus knows for sure that in OuterParser and InnerParser, Parser refers to the same type. 因此,编译器确切地知道在OuterParser和InnerParser中, Parser引用相同的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM