Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Type Inference Issues with Parametric Function

I have been learning Scala these days, and today I ran into some issue that I cannot understand.

Suppose we have the following parametric function definition:

def filter[T](source: List[T], predicate: T=>Boolean): List[T] = {
    source match {
        case Nil => Nil
        case x::xs => if(predicate(x)) x::filter(xs, predicate)
                  else filter(xs, predicate)
    }
}

Now, this works just fine if I invoke it as follows:

filter(List(1,2,3,4,5,6), ( (n:Int) => n % 2 == 0))

But if remove the type tag, it appears Scala cannot infer that the type of T is Int.

filter(List(1,2,3,4,5,6), ( n => n % 2 == 0))

So, I am forced to provide explicit type information in this call.

Does anybody know why Scala is not capable of inferring the type of T in this call. The list is evidently a List of Ints, I cannot see why it cannot infer that the type of n is also Int.

like image 490
Edwin Dalorzo Avatar asked Mar 04 '13 23:03

Edwin Dalorzo


People also ask

Does Scala support type inference?

The Scala compiler can infer the types of expressions automatically from contextual information. Therefore, we need not declare the types explicitly. This feature is commonly referred to as type inference. It helps reduce the verbosity of our code, making it more concise and readable.

What would be the type inferred by Scala compiler for variable?

Scala compiler can automatically infer types of each variable declared. If the value of a variable is declared in double-quotes it will automatically be inferred as String. Also, the compiler can infer any value in a single quote is inferred as Char. The compiler, by default it infer any number without decimal as Int.


2 Answers

Scala's type inference works per parameter list, not per parameter, so it hasn't resolved T to Int by the time it gets to the predicate in your second example. You can, however, get what you want by using two parameter lists:

def filter[T](source: List[T])(predicate: T => Boolean): List[T] =
  source match {
    case Nil => Nil
    case x :: xs =>
      if (predicate(x))
        x :: filter(xs)(predicate)
      else
        filter(xs)(predicate)
  }

Now the following will work just fine:

scala> filter(List(1, 2, 3, 4, 5, 6))((n => n % 2 == 0))
res0: List[Int] = List(2, 4, 6)

See my answer here for some additional discussion.

like image 145
Travis Brown Avatar answered Oct 27 '22 00:10

Travis Brown


You need to put the predicate in an other group of parameters to get inference to work:

def filter[T](source: List[T])(predicate: T=>Boolean): List[T] = {
    source match {
        case Nil => Nil
        case x::xs => if(predicate(x)) x::filter(xs)(predicate)
                   else filter(xs)(predicate)
    }
}

filter(List(1,2,3,4,5,6))(_ % 2 == 0)

Unfortunately it's a limitation of scala.

like image 45
Alois Cochard Avatar answered Oct 26 '22 22:10

Alois Cochard