2012-07-11 9 views
5

Quiero convertir implícitamente funciones de A => B a List[A] => List[B].elevación implícita en scala

me escribió la siguiente definición implícita:

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

Por desgracia, cuando escribo el siguiente código, implícita no se aplican:

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

Si anoto la función con el tiempo explícito, funciona bien.

¿Por qué? ¿Cómo puedo arreglarlo?

ACTUALIZACIÓN. Parece que el problema es específico de las funciones anónimas. 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) 
} 

El primero está compilado bien. El segundo está marcado como error

+0

¿Puede proporcionar el código que utiliza para implementar la 'implicit def'? –

+1

@ChrisJamesC Actualizado con un caso de prueba –

+2

¿Estás seguro de que necesitas/quieres hacer esto? 'map' compra mucha claridad para algunos personajes, y p. 'val plusOne: (List [Int]) => List [Int] = _ map (_ + 1)' es realmente más corto que su versión. –

Respuesta

6

Según The Scala Language Specification/Expresiones/funciones anónimas (6.23):

Si el tipo esperado de la función anónima es de la forma scala.Función n [S , y hellip ;, S n, R], el tipo esperado de correo es R ...

Por lo tanto, el tipo de resultado de la función se infiere como List[Int] a menos que se separe la definición de la función de la asignación de valores de función (para deshacerse del tipo esperado):

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

o especifique el tipo de función explícitamente:

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

(Scala 2.9.1-1 (Java HotSpot (TM) de 64 bits del servidor VM, Java 1.7.0_05)

Una primera observación: Si duplica fun2ListFun y cambiarle el nombre a, por ejemplo, `` fun2ListFun, obtendrá

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) 

parece como si el compilador considera tanto implícitos como sea aplicable.


Una segunda observación:

División

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

en

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

hace feliz el compilador.

1

La conversión implícita para el valor de entrada se compila. Así que sólo tenemos un problema para la salida de la función anónima

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

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

Un posible arreglo mediante una segunda conversión implícita:

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

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

Esta versión compila.

0

Parece que el compilador tiene dificultades para entender qué está sucediendo con el tipo de función. Si se le va a dar un poco de ayuda, que funcionaría:

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

scala> val f: List[Int] => List[Int] = ((_:Int) + 1):(Int => Int) 
f: (List[Int]) => List[Int] = <function1> 
Cuestiones relacionadas