5

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.

Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205

2 Answers2

8

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.

Community
  • 1
  • 1
Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • Additionally, invoking such HOFs is actually syntactically more natural when the `predicate` is specified in a separate parameter list (and one that has a single parameter and is rightmost, excepting any implicit parameter list). This is 'cause you don't need to nest the function argument inside the parens of the parameter list containing `source`. Because of the proviso "has a single parameter" you don't need to enclose it in parens at all, other than the parens (or braces) you'd use to enclose a function literal. – Randall Schulz Mar 05 '13 at 02:56
1

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.

Alois Cochard
  • 9,812
  • 2
  • 29
  • 30