2012-07-11 6 views
5

Ich möchte implizit Funktionen von A => B zu List[A] => List[B] konvertieren.Implizite Aufhebung in scala

Ich schrieb die folgende implizite Definition:

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

Leider, wenn ich den folgenden Code schreiben, implizite nicht angewandt werden:

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

Wenn ich die Funktion mit expliziter Zeit, es mit Anmerkungen versehen funktioniert gut.

Warum? Wie kann ich es reparieren?

UPDATE. Es scheint, dass das Problem für anonyme Funktionen spezifisch ist. Vergleich:

@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) 
} 

Der erste ist gut kompiliert. Der zweite wird als Fehler markiert

+0

Können Sie den Code angeben, den Sie verwenden, um das implizite Def zu implementieren? –

+1

@ChrisJamesC Aktualisiert mit einem Testfall –

+2

Sind Sie sicher, dass Sie dies tun müssen/wollen? "Karte" kauft viel Klarheit für ein paar Zeichen, und z.B. 'val plusOne: (Liste [Int]) => Liste [Int] = _ map (_ + 1)' ist tatsächlich kürzer als deine Version. –

Antwort

6

Nach The Scala Language Specification/Expressions/Anonyme Funktionen (6.23):

Wenn die erwartete Art der anonymen Funktion der Form ist scala.Funktion n [ S , & hellip ;, S n, R], die erwartete Art von e ist R ...

der Ergebnistyp der So, Funktion wird als List[Int] geschlossen werden, wenn Sie die Funktionsdefinition aus dem Funktionswert Zuordnung zu trennen (um loszuwerden, den erwarteten Typ):

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

oder geben Sie den Funktionstyp explizit an:

1

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

Eine erste Beobachtung: Wenn Sie duplizieren fun2ListFun und benennen Sie sie um, zum Beispiel `` fun2ListFun, werden Sie

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) 

es sieht aus, als, wenn der Compiler beide implicits als anwendbar erachtet.


Eine zweite Beobachtung:

Splitting

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

in

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

macht der Compiler glücklich.

1

Die implizite Konvertierung für den Eingabewert wird kompiliert. So haben wir nur ein Problem für die Ausgabe der anonymen Funktion

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) 
} 

Eine mögliche Lösung eine zweite implizite Konvertierung mit:

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) 
} 

Diese Version kompiliert.

0

Scheint der Compiler hat es schwer herauszufinden, was mit dem Typ der Funktion vorgeht. Wenn Sie ihm ein wenig Hilfe geben, würde es funktionieren:

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>