开发者

Method-Level Higher-Kinded Types in Scala

I've just started playing around with higher-kinded types in Scala and I'm experiencing behavior that I do not understand. I'm doing all of this in the REPL on Scala 2.9.0.1.

First I create a mapper trait so that I can map over the elements of any type M:

 trait Mapper {
    def mapper[M[_], A, B](m: M[A], f: A => B): M[B]
 }

Here's my implementation of the mapper:

 val mymapper = new Mapper {
  def mapper[List, Int, Double](m: List[Int], f: Int => Double): List[Double] = m.map(f)
 }

But the REPL complains...

 <console>:9: error: List does not take type parameters
   def mapper[List, Int, Double](m: List[Int], f: Int => Double): List[Double] = m.map(f)
                                                                  ^
开发者_运维技巧 <console>:9: error: List does not take type parameters
   def mapper[List, Int, Double](m: List[Int], f: Int => Double): List[Double] = m.map(f)
                                    ^

This code works fine if I move the declaration of M[_] to be at the class level:

trait Mapper[M[_]] {
  def mapper[A,B](m: M[A], f: A => B): M[B]
}
val mymapper = new Mapper[List] {
  def mapper[Int, Double](m: List[Int], f: Int => Double): List[Double] = m.map(f)
}
mymapper.mapper(List(1,2,3), (x: Int) => x.toDouble)
// returns List(1.0, 2.0, 3.0)

Why is this the case? Why is that Scala can figure out the correct type for M if it's located at a class-level, but fails at the method level?

Thanks!


This code does not mean what you think it means:

def mapper[List, Int, Double](m: List[Int], f: Int => Double): List[Double] = m.map(f)

List, Int and Double here are the names of type parameters, the exact types will be defined by the values used to call the method. Yes, they happen to also be the names of actual concrete types, but in this case you're shadowing that meaning.

If you use your original names of M, A and B, the error becomes clearer:

def mapper[M, A, B](m: M[A], f: A => B): M[B] = m.map(f)

M really does not take a type parameter...


It becomes even more obvious if you do the same thing with parameter names in your "working" example:

trait Mapper[M[_]] {
  def mapper[A,B](m: M[A], f: A => B): M[B]
}

val mymapper = new Mapper[List] {
  def mapper[A, B](m: List[A], f: A => B): List[B] = m.map(f)
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜