2016-10-18 1 views
1

Zuerst hatte ich geglaubt, dass Unterstrichen mit Schließungen zu machen (zB println _) für die Verwendung mit einem Pfeil nur eine Abkürzung waren (zB x => println x), aber ich habe gerade erfahren, vor kurzem, dass Sie auch die folgenden Aktionen durchführen:Was sind in Scala die Regeln für die Herstellung von Verschlüssen mit Unterstrichen?

def f(a: Int, b: Int) = a + 2 * b 
List(1, 2, 3).reduce(f _) 

Gegeben Meine bisherigen Annahmen, f _ sieht aus wie eine Schließung, die genau ein Argument akzeptiert und genau ein Argument an f übergibt. Ich nahm an, dass es mir sagen würde, dass es nicht kompilieren konnte, weil f zwei Argumente erwartet, und reduce sollte eine Funktion mit zwei Argumenten erwarten. Aber es funktioniert, als ob ich geschrieben hätte:

def f(a: Int, b: Int) = a + 2 * b 
List(1, 2, 3).reduce((x, y) => f(x, y)) 

Was geht hier vor? Welche Regeln gelten für das Erstellen von Closures mit Unterstrichen?

+2

In diesem Fall ist 'f _' ein Funktionstyp, der den Eta-Erweiterungsmechanismus verwendet. Das heißt, es übersetzt die Methode "f (a: Int, b: Int): Int" in "(Int, Int) => Int" (dh eine "Funktion2 [Int, Int, Int]"), die a ist Gültiger Typ zum Reduzieren. –

+0

(auch als eine schnelle Notiz, Ihre Funktion ist nicht assoziativ, die den Vertrag durch reduced) –

+0

@ math4tots auch, seien Sie sich bewusst, dass 'f _' und 'f (_)' sind zwei verschiedene Dinge. – fxlae

Antwort

3

Nichts besonderes los. Methode reduce nimmt eine Funktion, die zwei Int s und produziert eine Int, so dass es mit einem f funktioniert gut funktioniert. Beachten Sie, dass, wenn Sie sagen, f _, die tatsächlich zu x => f x erweitert (oder, im Falle von zwei Parametern wie hier, (x, y) => f(x, y)). Sie können auch einfach f angeben, die dann direkt ohne den zusätzlichen anonymen Funktions-Wrapper verwendet werden.

Umwandlung einer Methode in eine Funktion f _ heißt eta-expansion (vollständige Offenlegung: Ich schrieb diesen Artikel). Der Unterschied ist subtil; Funktion ist ein Wert, während eine Methode eine Methode ist, die Sie für ein Objekt aufrufen, für das sie definiert ist, z. myObject.myMethod. Funktion kann eigenständig sein, in Sammlungen etc. gehalten werden. Definieren Sie Ihre Methode f direkt als eine Funktion wäre oder, mit Typ Inferenz, val f = (a: Int, b: Int) => a + b.

BTW Ich sehe nicht, wie das eine Schließung ist.

+0

Was ist der Unterschied zwischen einer partiell angewendeten Funktion und einer eta-Erweiterung? Z.B. 'val k = f _ ', ist das nicht auch eine teilweise angewandte Funktion? – ceran

+0

@ceran Nein. Teilweise angewandte Funktion wäre 'f (42, _: Int)'. Oder wenn es curried als 'def f (a: Int) (b: Int)' dann kannst du 'f (42) _' sagen. Aber nur 'f _' zu sagen bedeutet, dass eine Methode 'f' in eine Funktion umgewandelt wird. Siehe auch Bearbeiten in meiner Antwort für weitere Erläuterungen. – slouc

+0

Hm Ich sehe den Unterschied nicht. Oderskys Scala-Buch sagt, dass in 'list.foreach (println _)' 'println _' eine teilweise angewandte Funktion darstellt. Sie müssen überhaupt keine Argumente liefern. – ceran

Verwandte Themen