3

I vergleicht zwei Möglichkeiten, ein higher-order function in Scala definieren:Currying vs. anonyme Funktion in Scala

def f1(elem: Int)(other: Int) = (elem == other) 

def f2(elem: Int) = (other: Int) => (elem == other) 

Die ersten verwenden currying während der zweite ein anonymous function verwendet.

Ich frage mich, was ist der Unterschied, wenn überhaupt, zwischen den beiden Ansätze in Bezug darauf, wie Scala sie implementiert und welche Version vorzuziehen ist?

Antwort

7

Die Implementierungen unterscheiden sich ziemlich vom Scala-Compiler. Die curried Version kompiliert die Parameter von un-currying auf eine Java-Methode nach unten:

def f1(elem: Int, other: Int): Boolean = elem.==(other); 

Die zweite Version ist eine Methode, die eine anonyme Funktion gibt (a Function1), so dass ihre Unterschriften völlig unterschiedlich sind. Obwohl sie oft austauschbar innerhalb Scala-Code verwendet werden kann, gibt es ein bisschen mehr generierten Code in der zweiten Version:

def f2(elem: Int): Function1 = (new <$anon: Function1>(elem): Function1); 

    @SerialVersionUID(value = 0) final <synthetic> class anonfun$f2$1 extends scala.runtime.AbstractFunction1$mcZI$sp with Serializable { 
    final def apply(other: Int): Boolean = anonfun$f2$1.this.apply$mcZI$sp(other); 
    <specialized> def apply$mcZI$sp(other: Int): Boolean = anonfun$f2$1.this.elem$1.==(other); 
    final <bridge> <artifact> def apply(v1: Object): Object = scala.Boolean.box(anonfun$f2$1.this.apply(scala.Int.unbox(v1))); 
    <synthetic> <paramaccessor> private[this] val elem$1: Int = _; 
    def <init>(elem$1: Int): <$anon: Function1> = { 
     anonfun$f2$1.this.elem$1 = elem$1; 
     anonfun$f2$1.super.<init>(); 
    () 
    } 
    } 

Ich würde nur betrachte die zweite Version in Fällen verwendet, wo suchte ich ausdrücklich zu arbeiten mit Function1 Objekte. Allerdings würde ich mich persönlich eher auf die Verwendung der Curry-Version beziehen, da man bei teilweiser Anwendung der ersten noch eine Function1 zurückbekommen kann. Die Curry-Version ist genauso leistungsfähig, erstellt aber keine Function1 Objekte, wenn Sie sie nicht benötigen.

scala> f1(1) _ 
res1: Int => Boolean = <function1> 
+0

danke für die Antwort. Wie produzieren Sie Java Code von Scala? würde auch etwas wie 'val f3 = (_: Int) == (_: Int); f3.curried' leiden unter dem gleichen Problem, das Sie bei 'f2' festgestellt haben? –

+0

Sie können nicht wirklich lesbaren Java-Byte-Code von Scala erzeugen (kann aber Byte-Code erzeugen). Ich habe '-Xprint: jvm' verwendet, um den Code in meiner Antwort zu erzeugen, der eine der letzten Phasen des Scala-Compilers ist. 'f3.curried' würde zwei anonyme Funktionen anstelle von einer erzeugen, so dass mehr Byte-Code als' f2' erzeugt würde. –

Verwandte Themen