Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 499
Konstantin Solomatov Avatar asked Jul 11 '12 21:07

Konstantin Solomatov


2 Answers

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
like image 85
Pavel Fatin Avatar answered Nov 05 '22 05:11

Pavel Fatin


(Scala 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05)

A first observation: If you duplicate fun2ListFun and rename it to, e.g.,``fun2ListFun, you'll get

found   : String => <error>
 required: List[String] => List[Int]

Note that implicit conversions are not applicable because they are ambiguous:
 both method fun2ListFun2 of type [X, Y](f: X => Y)List[X] => List[Y]
 and method fun2ListFun of type [X, Y](f: X => Y)List[X] => List[Y]
 are possible conversion functions from String => <error> to List[String] => List[Int]
  val v: List[String] => List[Int] = ((x: String) => x.length)

It looks as if the compiler considers both implicits as applicable.


A second observation:

Splitting

val v: List[String] => List[Int] = ((x: String) => x.length) /* Error*/

into

val f = ((x: String) => x.length)
val v: List[String] => List[Int] = f /* Works */

makes the compiler happy.

like image 1
Malte Schwerhoff Avatar answered Nov 05 '22 05:11

Malte Schwerhoff