Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala anonymous function missing parameter type error

Tags:

scala

I wrote the following

def mapFun[T, U](xs: List[T], f: T => U): List[U] = (xs foldRight List[U]())( f(_)::_ )

and when I did

def f(x: Int):Int=x*x
mapFun(List(1,2,3), f)

It worked fine. However, I really wanted to make the following work too

mapFun(List(1,2,3), x=>x*x)

It complains about "missing parameter type". I know that I could use currying, but is there any way to still use anonymous function for non-currying def I had above?

like image 392
Qiang Li Avatar asked Oct 29 '12 02:10

Qiang Li


2 Answers

It seems to me that because "f" is in the same parameter list as "xs", you're required to give some information regarding the type of x so that the compiler can solve it.

In your case, this will work:

mapFun(List(1,2,3) , (x: Int) => x * x)  

Do you see how I'm informing the compiler that x is an Int?

A "trick" that you can do is currying f. If you don't know what currying is check this out: http://www.codecommit.com/blog/scala/function-currying-in-scala

You will end up with a mapFun like this:

def mapFun[T, U](xs: List[T])(f: T => U): List[U] = 
    (xs foldRight List[U]())( f(_)::_ )

And this will work:

mapFun(List(1,2,3))(x => x * x)

In the last call, the type of x is resolved when the compiler checks the first parameter list.

EDIT:

As Dominic pointed out, you could tell the compiler what your types are. Leading to:

mapFun[Int, Int](List(1,2,3), x => x * x)

Cheers!

like image 86
wleao Avatar answered Nov 10 '22 14:11

wleao


The limitation of scala's type system that you're running into here is that the type information flows from left to right across parameter groups and does not flow from left to right within a parameter group.

What this means is that specifying the type parameter T by providing a List[Int] will not provide that information to other parameters within the group like f. Which results in a missing parameter type error. But it will provide it to f if f were a part of the next parameter group. This is why the curried function approach works.

i.e. if you defined it like this:

def mapFun[T, U](xs: List[T])(f: T => U): List[U] = (xs foldRight List[U]())( f(_)::_ )

The type parameter T that you define in the first parameter group: (xs: List[T]) as Int will be made available to the next parameter group: (f: T => U). So now you do not have to explicitly specify T at the call site.

like image 17
Ratan Sebastian Avatar answered Nov 10 '22 15:11

Ratan Sebastian