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.

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.