开发者

Scala: constructor arguments involving inner types of bounded types

开发者 https://www.devze.com 2023-03-04 03:26 出处:网络
In scala 2.9.0.RC3, I defined a trait for parsers and a concrete example of a parser: trait Parser { type Result

In scala 2.9.0.RC3, I defined a trait for parsers and a concrete example of a parser:

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

Now I'd like to be able to compare parsed values:

class Comparator[P <: Parser](p: P) {
  def compare(s1: String, s2: String) = p.p开发者_StackOverflow中文版arse(s1) == p.parse(s2)
}

This works fine, I can do:

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

And it produces false, as expected. Unfortunately, it gets downhill from here. To allow for fancier comparison, I define:

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

And try to invoke it as before:

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

But then:

error: type mismatch;
 found   : (this.Parser#Result, this.Parser#Result) => Boolean
 required: (this.IdParser#Result, this.IdParser#Result) => Boolean
Error occurred in an application involving default arguments.
println(new CustomisableComparator(new IdParser).compare("a", "b"))
        ^

Oh, well, I'd expect the type variable P in CustomisableComparator to be bound to IdParser, so I'm not quite sure why scala thinks it's Parser in the default value. Let's forget about the default then and provide the value explicitly:

println(new CustomisableComparator(new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))
error: type mismatch;
 found   : (this.IdParser#Result, this.IdParser#Result) => Boolean
 required: (?#Result, ?#Result) => Boolean

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

This is well confusing. If I don't provide a value, the compiler expects (this.IdParser#Result, this.IdParser#Result) => Boolean; once I do provide a value of this type, it expects (?#Result, ?#Result) => Boolean. Can anyone explain what is going on here?


You're just asking too much of type inference. You seem to think it's going to backtrack for you, and it isn't.

Both your examples compile if you supply the type:

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

Or, you will get better type inference in these situations (it goes from left to right) if you use additional parameter lists in strategic locations.

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"))
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号