Entspricht eine verkettete Methode, für die nur ein Parameter pro Methode erforderlich ist, dem Currying?

15

Ich habe in letzter Zeit mit Ruby rumgespielt und mich gefragt, ob es mit rein objektorientierten Sprachen (und sogar mit Methoden, die nicht rein sind) gleichzusetzen ist, wenn man nur einen Parameter verwendet und dann verkettet Stil? Wenn nein, warum nicht? Ich würde mich über eine detaillierte, sogar strenge Antwort zu diesem Thema freuen.

Weltingenieur
quelle

Antworten:

14

Die Verkettung von Methoden in objektorientierten Sprachen unterscheidet sich ein wenig vom Currying. Per Definition ist das Ergebnis des Currys eine eingeschränktere Form der ursprünglichen Funktion . Durch Konvention ist das Ergebnis des Verfahrens Verkettungs eine modifizierte Form des Originals (in der Regel nicht-Funktion) Objekt . Die Methodenverkettung kann mit nicht verwandten Methoden derselben Klasse verwendet werden, wohingegen beim Currying eine Funktion zurückgegeben wird, bei der ein oder mehrere Parameter der ursprünglichen Funktion festgelegt (vorgegeben) sind.

In Java sieht die Methodenverkettung folgendermaßen aus:

String myString = new StringBuilder("Hi ").append(firstName)
                                          .append(" ")
                                          .append(lastName)
                                          .append("!")
                                          .toString();

Daher gibt jeder dieser Aufrufe der .append () -Methode einen Zeiger auf das anonyme StringBuilder-Objekt zurück. Dieses Objekt ist nach jedem .append () abgeschlossen und keine Funktion.

Im Gegensatz dazu ist in Scala eine teilweise Anwendung oder ein Currying wie folgt:

def simple(x:Int, y:Int, z:Int) = x * (y + z)
val simpler = simple(2, _:Int, _:Int)
simpler(3, 4) => 14

(Probe aus Daniel Yankowskys Blog )

simpler()In diesem Beispiel ist eine Wrapper-Funktion für simple(). simpler()ist immer noch eine Funktion, die mehr Parameter benötigt, bevor sie zu etwas anderem als einer begrenzten Version von sich selbst ausgewertet werden kann.

EDIT: Wenn ich das einen Tag später lese , denke ich, dass "Wrapper-Funktion" der Schlüssel ist. Currying oder teilweise Anwendung kann am besten in Java mit Wrapper-Methoden simuliert werden.

public interface Simpler {
    public int apply(int y, int z);
}

public class Simple {
    public int apply(int x, int y, int z) { return x * (y + z); }

    public Simpler partiallyApply(final int x) {
        final simple = this;
        return new Simpler() {
            @Override
            public int apply(int y, int z) {
                // x is the final int parameter to partiallyApply()
                simple.apply(x, y, z);
            }
        }
    }
}

: END-EDIT

Die Methodenverkettung kann einer Teilanwendung oder einer Teilanwendung ähnlich sein, sie kann jedoch nur mit Methoden äquivalent sein, die andere Methoden zurückgeben (siehe Functors). Anschließend müssen die Methoden mit Rückgabetypen eingerichtet werden, die die Ausführung oder Teilanwendung sinnvoll modellieren.

Die Verkettung von Methoden wird häufiger verwendet, um so etwas wie eine verzögerte Auswertung zu implementieren, wie dies beim Entwurfsmuster "Builder" und den neuen Schnittstellen der Collections Library in Java 8 der Fall ist .

Ich hoffe das hilft.

GlenPeterson
quelle
+1: Ich wusste das, aber ich glaube nicht, dass ich es so gut hätte artikulieren können wie Sie.
Peter Rowell
Schön erklärt, hier ist ein grünes Häkchen und eine positive Bewertung für Ihre Probleme.
Ingenieur Welt
Frage zu dem sehr schönen Beispiel von StringBuilder - ohne den toString()Aufruf wiederholen wir nicht effektiv die Absicht, in unserem Aufruf mitzuwirken? Ich versuche nur, das Konzept des Lehrens in OO klar zu machen.
Sridhar Sarnobat
1
@ Sridhar-Sarnobat Eine Curry-Funktion gibt eine andere Funktion mit weniger Parametern zurück. Die eliminierten Parameter werden in der zurückgegebenen Funktion in interne Konstanten umgewandelt. Einige Objekte werden in Java 8 wie Funktionen behandelt, was zu Verwirrung führen kann, aber StringBuilder gehört nicht dazu. Hmm, innerhalb von StringBuilder ist die append(charSeq)Funktion eine gewöhnliche Form der insert(destOffset, charSeq)Funktion, wobei destOffsetimmer die Länge des StringBuilder angegeben ist.
GlenPeterson