Higher Level Method Types in Scala

I just started playing with the higher type types in Scala and I am experiencing behavior that I do not understand. I do all this in REPL on Scala 2.9.0.1.

First I create a mapper property so that I can display elements of any type M:

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

Here is my mapper implementation:

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

But 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 [_] 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 so? Why can Scala determine the correct type for M if it is at the class level but does not work at the method level?

Thanks!

+4
source share
1 answer

This code does not mean that you think it means:

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

The list, Int and Double here are the names of the type parameters, the exact types will be determined by the values ​​used to call the method. Yes, they are also names of specific concrete types, but in this case you obscure this meaning.

If you use the original names 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 accept a type parameter ...


This becomes even more obvious if you do the same 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) } 
+8
source

All Articles