【问题标题】:Scala: constructor arguments involving inner types of bounded typesScala:涉及有界类型内部类型的构造函数参数
【发布时间】:2011-05-07 08:32:07
【问题描述】:

在 scala 2.9.0.RC3 中,我为解析器定义了一个特征和一个解析器的具体示例:

trait Parser {
  type Result
  def parse(s: String): Result
}

class IdParser extends Parser {
  case class Result(s: String)
  def parse(s: String) = new Result(s)
}

现在我希望能够比较解析后的值:

class Comparator[P <: Parser](p: P) {
  def compare(s1: String, s2: String) = p.parse(s1) == p.parse(s2)
}

这很好,我可以做到:

println(new Comparator(new IdParser).compare("a", "b"))

它会产生 false,正如预期的那样。不幸的是,它从这里开始走下坡路。为了更好地进行比较,我定义:

class CustomisableComparator[P <: Parser](p: P, 
      cmp: (P#Result, P#Result) => Boolean = (r1: P#Result, r2: P#Result) => r1 == r2) {
  def compare(s1: String, s2: String) = cmp(p.parse(s1), p.parse(s2))
} 

并尝试像以前一样调用它:

println(new CustomisableComparator(new IdParser).compare("a", "b"))

然后:

错误:类型不匹配; 找到 : (this.Parser#Result, this.Parser#Result) => 布尔值 必需:(this.IdParser#Result, this.IdParser#Result) => 布尔值 涉及默认参数的应用程序发生错误。 println(new CustomisableComparator(new IdParser).compare("a", "b")) ^

哦,好吧,我希望CustomisableComparator 中的类型变量P 绑定到IdParser,所以我不太清楚为什么scala 认为它的默认值是Parser。让我们忘记默认值并明确提供值:

println(new CustomisableComparator(new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))
错误:类型不匹配; 找到 : (this.IdParser#Result, this.IdParser#Result) => 布尔值 必需: (?#Result, ?#Result) => 布尔值 println(new CustomisableComparator(new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b")) ^

这很令人困惑。如果我不提供值,编译器需要(this.IdParser#Result, this.IdParser#Result) =&gt; Boolean;一旦我确实提供了这种类型的值,它就需要(?#Result, ?#Result) =&gt; Boolean。谁能解释这里发生了什么?

【问题讨论】:

    标签: scala


    【解决方案1】:

    你对类型推断的要求太多了。你似乎认为它会为你倒退,但事实并非如此。

    如果您提供类型,您的两个示例都会编译:

    println(new CustomisableComparator[Parser](new IdParser).compare("a", "b"))
    println(new CustomisableComparator[IdParser](new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))
    

    或者,如果您在战略位置使用额外的参数列表,您将在这些情况下获得更好的类型推断(从左到右)。

    class CustomisableComparator2[P <: Parser](p: P)(cmp: (P#Result, P#Result) => Boolean = ((x: P#Result, y: P#Result) => x == y)) {
      def compare(s1: String, s2: String) = cmp(p.parse(s1), p.parse(s2))
    }
    // type parameter successfully inferred
    println(new CustomisableComparator2(new IdParser)((r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))
    

    【讨论】:

    • 感谢您的解决方案。我仍然对使用默认和显式参数时为什么“必需”类型不同感到困惑。第一个“必需”表明编译器能够正确推断函数的类型。在第二种情况下,它突然失去了这种能力。我对推理者应该能够做什么的期望是通过对 Haskell 的短暂接触而设定的。它似乎总是能够至少推断出我所能推断的更多,而且往往更多。在这种情况下,推断对我来说似乎很明显,所以我希望 scalac 也能弄清楚。
    猜你喜欢
    • 2021-06-24
    • 1970-01-01
    • 2019-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 2013-03-16
    • 2010-12-05
    相关资源
    最近更新 更多