Ein reales Beispiel für die Verwendung der Curry-Funktion? [geschlossen]

8

Ich hatte Mühe, ein reales Beispiel für die Verwendung der Curry-Funktion zu finden und den Vorteil der Verwendung von Curry zu nutzen.

Wenn ich die Curry-Funktion google, sehe ich oft das Beispiel wie

let add = x => y => x + y;
let add10 = add(10);
console.log(add10(20));

Ich muss sagen, dass ich den Wert der Verwendung von Curry in diesem Beispiel wirklich nicht sehe.

Nachdem ich die Antworten in diesem SO /programming/113780/javascript-curry-what-are-the-practical-applications gelesen habe, sehe ich immer noch keinen Nutzen darin, es zu verwenden.

Zum Beispiel gibt die Antwort mit der höchsten Punktzahl ein Beispiel für einen Konverter, aber dieses Beispiel kann ohne Curry umgeschrieben werden, wie eine andere Antwort zeigt.

Ich habe auch die Antworten durchgelesen. Was ist der Vorteil des Curry? (obwohl die Diskussion nicht auf Javascript beschränkt ist) Ich habe immer noch das Gefühl, dass die Curry-Version ohne Curry (in js) umgeschrieben werden kann.

Kann mir jemand den "echten" Vorteil / Nutzen der Verwendung von Curry in Javascript zeigen?

---- Update ----

Abgesehen von den Antworten, die ich erhalten habe, finde ich auch das Protokollbeispiel hier, das den Vorteil der Verwendung zeigt.

Qiulang
quelle
2
Ich bin damit einverstanden, dass die meisten grundlegenden Beispiele für Curry, die Sie online finden, äußerst unscheinbar sind.
user949300
@ user949300 Übrigens, ich verstehe wirklich nicht, warum meine Frage abgelehnt wurde. Ist das nicht eine "gültige" Frage, wenn Sie an js Curry denken? Ich habe mir Sorgen gemacht, dass es bei SO geschlossen sein wird, also habe ich hier gefragt. :(
Qiulang
Ich fand Currying meistens nützlich, wenn eine externe lib-Funktion eine Funktion (z. B. einen Rückruf) erwartet, die eine bestimmte Anzahl von Argumenten akzeptiert, und Sie eine Funktion (z. B. einen Handler) haben, die mehr Argumente akzeptiert, aber Sie möchten konstante Werte für diese zusätzlichen Argumente übergeben. Eine Teilkopie ist dann besser lesbar als eine
Pfeilfunktion
3
"Ich habe immer noch das Gefühl, dass die Curry-Version ohne Curry umgeschrieben werden kann" - Das ist trivial, denn darum geht es beim Curry. Der springende Punkt beim Currying ist die Beobachtung, dass jede Funktion von n Parametern als Funktion von n-1 Parametern umgeschrieben werden kann, was eine Funktion zurückgibt, die den n-ten Parameter annimmt. Beachten Sie auch, dass diese Aussage für so ziemlich alles gilt. Jede forSchleife kann als whileSchleife umgeschrieben werden . Jede ifAnweisung kann als whileSchleife umgeschrieben werden . Jede whileSchleife kann als umgeschrieben werden goto. Das heißt nicht, dass sie nicht nützlich sind.
Jörg W Mittag

Antworten:

8

Ich habe selbst kaum Currying verwendet, aber hier ist ein aktuelles Beispiel, bei dem es sich als nützlich erwiesen hat. Ich habe für das Spiel Battlesnake programmiert , aber dies würde für viele Spiele gelten. Sie bieten Ihnen verschiedene Arrays, die den Standort Ihrer Schlange, der feindlichen Schlangen und des Futters angeben. Angenommen, Sie erwägen einen Umzug zu einem bestimmten {x, y} -Punkt und möchten überprüfen, ob er eine andere Schlange, ein anderes Futter oder sogar sich selbst enthält. Der erste Durchgang wäre, Code wie diesen zu schreiben (ich werde eine Mischung aus Funktion und neuen Pfeilen verwenden)

// utility function
function samePoint(p1, p2) {
  return (p1.x === p2.x) && (p1.y === p2.y);
}

und irgendwo im Code gehen

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some((p) => samePoint(p, possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Nicht schlecht, aber, da Sie dies an vielen Stellen in Ihrem Code tun werden, etwas langweilig und klobig. Und meiner Erfahrung nach ist es einfach, die beiden Argumente durcheinander zu bringen. :-( Das zugrunde liegende Problem ist, dass some()(oder find()) eine Funktion akzeptiert wird, die nur ein einziges Argument akzeptiert , und Sie wirklich zwei Argumente benötigen , die beiden Punkte. Sie denken also an Curry! Hier würden viele Pfeile verwenden, ich finde verschachtelte Funktionen klarer:

function samePointAs(p1) {
  return function(p2) {
    return samePoint(p1, p2);
  }
}

Dann wird Ihr "Ist das Essen" -Test

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some(samePointAs(possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Werden Sie dadurch ein Internet-Millionär? Wahrscheinlich nicht. Dies vereinfacht und verdeutlicht in diesem Fall Ihren Code.

user949300
quelle
Hallo, ich mag dein Beispiel, also habe ich deine Antwort als akzeptierte Antwort markiert. Vielen Dank.
Qiulang
Hallo, meine Frage wird zurückgestellt. Es wurde sogar gelöscht. Ich habe versucht, es zu bearbeiten, damit es ohne Erfolg auf Eis gelegt wird. Ich habe mich gefragt, ob Sie mir beim Bearbeiten helfen können.
Qiulang
14

Currying in Ihrem Beispiel macht nicht wirklich Sinn, da stimme ich zu. Um die Funktionalität des Curry zu sehen, müssen Sie es mit Funktionen höherer Ordnung kombinieren: Funktionen, die andere Funktionen als Parameter verwenden.

Das typischste Beispiel hierfür ist das Zuordnen, Filtern und Reduzieren. Eine weitere häufige Situation sind Rückrufe. Wenn Sie eine Funktion teilweise anwenden, können Sie die teilweise angewendete Funktion an diese Funktionen höherer Ordnung übergeben. Currying ist sinnvoll, wenn Sie eine Funktion meistens für eine Teilanwendung verwenden möchten, damit sie an eine andere Funktion höherer Ordnung übergeben werden kann.

Ein anschaulicheres Beispiel könnte folgendermaßen aussehen:

let array1 = [1, 4, 9, 16];
let add = x => y => x + y;
array2 = array1.map(foo ? add(10) : add(20));

Currying ist niemals notwendig, ja, da Sie immer eine anonyme / Pfeil-Funktion aus einer regulären Funktion erstellen können, wenn Sie sie benötigen. In einigen Situationen kann es jedoch sehr praktisch sein, eine Curry-Funktion im Vergleich zu einer regulären Funktion zu haben (und in anderen Situationen ist es einfach Dinge nervig und langsam machen).

Lie Ryan
quelle
2
"Aber in manchen Situationen kann es sehr praktisch sein, eine Curry-Funktion im Vergleich zu einer normalen zu haben." Können Sie ein Beispiel dafür geben? Vielen Dank!
Qiulang
@Qiulang Ein Beispiel ist, wenn Sie eine Reihe von Konfigurationslogiken haben, die steuern, wie eine Funktion mit vielen Parametern aufgerufen wird. Wenn Sie keine Curry-Funktion haben, müssen Sie häufig ein Objekt mit einer fließenden API erstellen oder eine Art clone_and_update () -Methode bereitstellen, oder Sie müssen eine separate Builder-Klasse erstellen, um den Funktionsparameter zu erstellen inkrementell. Ein typisches Beispiel hierfür ist der Abfrage-Builder eines ORM. Mit der Curry-Funktion können Sie die Funktion bei jedem Schritt wie gewohnt aufrufen.
Lie Ryan
@LieRyan In JavaScript , wo es so trivial ist, ein Optionsobjekt mit zu erstellen {}, habe ich Builder-Klassen nicht als sehr nützlich oder allgemein empfunden . Können Sie einige Beispiele anführen?
user949300
1
@ user949300 Das Erstellen von zwanzig Objekten mit zehn Elementen, die sich nur durch einen oder zwei Parameter unterscheiden, ist in JS nicht einfacher als in anderen Sprachen. Mit einem unveränderlichen Builder-Objekt, das eine fließende Schnittstelle verwendet, können Sie stattdessen das Basis-Konfigurationsobjekt erstellen und dann einfach verzweigen, um verschiedene Argumentmengen zu erstellen. Diese Art von Muster sieht im Anwendungscode oft zu schwer aus, ist jedoch für Bibliotheks- / Framework-Autoren ziemlich häufig.
Lie Ryan
1
Punkt genommen, aber @LieRyan mit dem Newfangled ist Object.assign()es ziemlich einfach, von einer Basiskonfiguration abzuzweigen.
user949300