Search code examples
scalaimplicits

Implicit lifting in scala


I want to implicitly convert functions from A => B to List[A] => List[B].

I wrote the following implicit definition:

implicit def lift[A, B](f: A => B): List[A] => List[B] = ...

Unfortunately, when I write the following code, implicit aren't applied:

val plusOne: (List[Int]) => List[Int] = (x: Int) => (x + 1)

If I annotate the function with explicit time, it works fine.

Why? How can I fix it?

UPDATE. It seems that the problem is specific to anonymous functions. Compare:

@Test
def localLiftingGenerics {
  implicit def anyPairToList[X, Y](x: (X, Y)): List[X] => List[Y] = throw new UnsupportedOperationException  

  val v: List[String] => List[Int] = ("abc", 239)
}

@Test
def localLiftingFuns {
  implicit def fun2ListFun[X, Y](f: X => Y): List[X] => List[Y] = throw new UnsupportedOperationException

  val v: List[String] => List[Int] = ((x: String) => x.length)
}

The first one is compiled well. The second one is marked as error


Solution

  • According to The Scala Language Specification / Expressions / Anonymous Functions (6.23):

    If the expected type of the anonymous function is of the form scala.Functionn[S1, …, Sn, R], the expected type of e is R ...

    So, the result type of the function will be inferred as List[Int] unless you separate the function definition from the function value assignment (to get rid of the expected type):

    val function = (x: Int) => (x + 1)
    val plusOne: (List[Int]) => List[Int] = function
    

    or specify the function type explicitly:

    val plusOne: (List[Int]) => List[Int] = ((x: Int) => (x + 1)): Int => Int