Ich habe in mehreren Artikeln und Blogs Verweise auf Curry-Funktionen gesehen, aber ich kann keine gute Erklärung finden (oder zumindest eine, die Sinn macht!).
652
Ich habe in mehreren Artikeln und Blogs Verweise auf Curry-Funktionen gesehen, aber ich kann keine gute Erklärung finden (oder zumindest eine, die Sinn macht!).
curry
unduncurry
Funktionen von Haskell. Wichtig ist hierbei, dass diese Isomorphismen im Voraus festgelegt und daher in die Sprache "eingebaut" werden.add x y = x+y
(curried) unterscheidet sich vonadd (x, y)=x+y
(uncurried)Antworten:
Currying ist, wenn Sie eine Funktion, die mehrere Argumente akzeptiert, in eine Reihe von Funktionen aufteilen, die jeweils nur ein Argument enthalten. Hier ist ein Beispiel in JavaScript:
Dies ist eine Funktion, die zwei Argumente, a und b, akzeptiert und deren Summe zurückgibt. Wir werden jetzt diese Funktion curry:
Dies ist eine Funktion, die ein Argument a verwendet und eine Funktion zurückgibt, die ein anderes Argument b verwendet, und diese Funktion gibt ihre Summe zurück.
Die erste Anweisung gibt 7 zurück, wie die add (3, 4) -Anweisung. Die zweite Anweisung definiert eine neue Funktion namens add3, die ihrem Argument 3 hinzufügt. Dies ist, was manche Leute eine Schließung nennen können. Die dritte Anweisung verwendet die Operation add3, um 3 zu 4 zu addieren, wodurch wiederum 7 erzeugt wird.
quelle
[1, 2, 3, 4, 5]
, die Sie mit einer beliebigen Zahl multiplizieren möchten. In Haskell kann ich schreibenmap (* 5) [1, 2, 3, 4, 5]
, um die gesamte Liste mit zu multiplizieren5
und so die Liste zu generieren[5, 10, 15, 20, 25]
.map
muss eine Funktion sein, die nur 1 Argument akzeptiert - ein Element aus der Liste. Multiplikation - als mathematisches Konzept - ist eine binäre Operation; Es dauert 2 Argumente. In Haskell*
gibt es jedoch eine Curry-Funktion, ähnlich der zweiten Versionadd
in dieser Antwort. Das Ergebnis von(* 5)
ist eine Funktion, die ein einzelnes Argument nimmt und mit 5 multipliziert und die es uns ermöglicht, es mit map zu verwenden.In einer Algebra von Funktionen ist der Umgang mit Funktionen, die mehrere Argumente annehmen (oder einem Argument, das ein N-Tupel entspricht), etwas unelegant - aber wie Moses Schönfinkel (und unabhängig davon Haskell Curry) bewiesen hat, ist es nicht erforderlich: Sie alle Need sind Funktionen, die ein Argument annehmen.
Wie gehen Sie mit etwas um, als das Sie sich natürlich ausdrücken würden
f(x,y)
? Nun, Sie nehmen das als Äquivalent zuf(x)(y)
-f(x)
, nennen esg
, ist eine Funktion, und Sie wenden diese Funktion auf any
. Mit anderen Worten, Sie haben nur Funktionen, die ein Argument annehmen - aber einige dieser Funktionen geben andere Funktionen zurück (die AUCH ein Argument annehmen ;-).Wie üblich hat Wikipedia einen schönen zusammenfassenden Eintrag dazu, mit vielen nützlichen Hinweisen (wahrscheinlich auch in Bezug auf Ihre Lieblingssprachen ;-) sowie einer etwas strengeren mathematischen Behandlung.
quelle
div :: Integral a => a -> a -> a
- diese mehreren Pfeile beachten? "Map a to function Mapping a to a" ist eine Lesung ;-). Sie könnten ein (einzelnes) Tupelargument fürdiv
& c verwenden, aber das wäre in Haskell wirklich anti-idiomatisch.Hier ist ein konkretes Beispiel:
Angenommen, Sie haben eine Funktion, die die auf ein Objekt wirkende Gravitationskraft berechnet. Wenn Sie die Formel nicht kennen, finden Sie sie hier . Diese Funktion verwendet die drei erforderlichen Parameter als Argumente.
Wenn Sie jetzt auf der Erde sind, möchten Sie nur Kräfte für Objekte auf diesem Planeten berechnen. In einer funktionalen Sprache könnten Sie die Masse der Erde an die Funktion übergeben und sie dann teilweise bewerten. Was Sie zurückbekommen würden, ist eine weitere Funktion, die nur zwei Argumente verwendet und die Gravitationskraft von Objekten auf der Erde berechnet. Dies nennt man Currying.
quelle
Currying ist eine Transformation, die auf Funktionen angewendet werden kann, damit diese ein Argument weniger als zuvor verwenden können.
In F # können Sie beispielsweise eine Funktion folgendermaßen definieren:
Hier nimmt die Funktion f die Parameter x, y und z und summiert sie so: -
Rückgabe 6.
Aus unserer Definition können wir daher die Curry-Funktion für f definieren: -
Wobei 'fun x -> fx' eine Lambda-Funktion ist, die x => f (x) in C # entspricht. Diese Funktion gibt die Funktion ein, die Sie curry möchten, und gibt eine Funktion zurück, die ein einzelnes Argument verwendet und die angegebene Funktion zurückgibt, wobei das erste Argument auf das Eingabeargument gesetzt ist.
Mit unserem vorherigen Beispiel können wir ein Curry von f erhalten, indem wir:
Wir können dann Folgendes tun: -
Was uns eine Funktion f1 liefert, die f1 yz = 1 + y + z entspricht. Dies bedeutet, dass wir Folgendes tun können:
Welches gibt 6 zurück.
Dieser Prozess wird oft mit "Teilfunktionsanwendung" verwechselt, die folgendermaßen definiert werden kann:
Obwohl wir es auf mehr als einen Parameter erweitern können, dh:
Eine Teilanwendung übernimmt die Funktion und die Parameter und gibt eine Funktion zurück, für die ein oder mehrere Parameter erforderlich sind. Wie die beiden vorherigen Beispiele zeigen, wird sie direkt in die Standarddefinition der F # -Funktion implementiert, sodass wir das vorherige Ergebnis folgendermaßen erzielen können:
Welches ergibt ein Ergebnis von 6.
Abschließend:-
Der Unterschied zwischen Currying und Teilfunktionsanwendung besteht darin, dass:
Currying nimmt eine Funktion und stellt eine neue Funktion bereit, die ein einzelnes Argument akzeptiert und die angegebene Funktion zurückgibt, wobei das erste Argument auf dieses Argument gesetzt ist. Dies ermöglicht es uns, Funktionen mit mehreren Parametern als eine Reihe von Funktionen mit einem Argument darzustellen . Beispiel:-
Die Anwendung von Teilfunktionen ist direkter - sie verwendet eine Funktion und ein oder mehrere Argumente und gibt eine Funktion zurück, bei der die ersten n Argumente auf die angegebenen n Argumente gesetzt sind. Beispiel:-
quelle
Es kann eine Möglichkeit sein, Funktionen zu verwenden, um andere Funktionen zu erstellen.
In Javascript:
Würde es uns erlauben, es so zu nennen:
Wenn dies ausgeführt wird,
10
wird das als übergebenx
;was bedeutet, dass uns diese Funktion zurückgegeben wird:
Also wenn du anrufst
Sie rufen wirklich an:
Wenn Sie dies tun:
es ist das gleiche wie:
addTen()
Wir addieren also immer zehn zu allem, was wir übergeben. Wir können ähnliche Funktionen auf die gleiche Weise ausführen:Die offensichtliche Folgefrage ist nun, warum um alles in der Welt würden Sie das jemals tun wollen? Es verwandelt eine eifrige Operation
x + y
in eine Operation , die träge durchlaufen werden kann, was bedeutet, dass wir mindestens zwei Dinge tun können: 1. teure Operationen zwischenspeichern 2. Abstraktionen im funktionalen Paradigma erzielen.Stellen Sie sich vor, unsere Curry-Funktion sieht folgendermaßen aus:
Wir könnten diese Funktion einmal aufrufen und dann das Ergebnis weitergeben, um es an vielen Stellen zu verwenden, was bedeutet, dass wir die rechenintensiven Dinge nur einmal ausführen:
Auf ähnliche Weise können wir Abstraktionen erhalten.
quelle
Eine Curry-Funktion ist eine Funktion mehrerer Argumente, die so umgeschrieben wurden, dass sie das erste Argument akzeptiert und eine Funktion zurückgibt, die das zweite Argument akzeptiert, und so weiter. Dadurch können Funktionen mehrerer Argumente einige ihrer ursprünglichen Argumente teilweise anwenden.
quelle
map
eine Funktionf
über eine Liste von Listenxss
ausführen möchten, können Sie dies tunmap (map f) xss
.Hier ist ein Spielzeugbeispiel in Python:
(Verwenden Sie einfach die Verkettung über +, um Ablenkungen für Nicht-Python-Programmierer zu vermeiden.)
Bearbeitung zum Hinzufügen:
Siehe http://docs.python.org/library/functools.html?highlight=partial#functools.partial , in dem auch die Unterscheidung zwischen Teilobjekt und Funktion in der Art und Weise angezeigt wird, wie Python dies implementiert.
quelle
Beim Currying wird eine Funktion von aufrufbar
f(a, b, c)
in aufrufbar wie übersetztf(a)(b)(c)
.Andernfalls wird Currying ausgeführt, wenn Sie eine Funktion, die mehrere Argumente enthält, in eine Reihe von Funktionen aufteilen, die Teil der Argumente sind.
Currying ist buchstäblich eine Transformation von Funktionen: von einer Art des Aufrufs in eine andere. In JavaScript erstellen wir normalerweise einen Wrapper, um die ursprüngliche Funktion beizubehalten.
Curry ruft keine Funktion auf. Es verwandelt es einfach.
Lassen Sie uns eine Curry-Funktion erstellen, die das Currying für Funktionen mit zwei Argumenten ausführt. Mit anderen Worten,
curry(f)
für zwei Argumentef(a, b)
übersetzt es inf(a)(b)
Wie Sie sehen können, besteht die Implementierung aus einer Reihe von Wrappern.
curry(func)
ist ein Wrapperfunction(a)
.sum(1)
, wird das Argument in der Lexikalischen Umgebung gespeichert und ein neuer Wrapper zurückgegebenfunction(b)
.sum(1)(2)
schließlich diefunction(b)
Bereitstellung von 2 auf und leitet den Aufruf an die ursprüngliche Summe mit mehreren Argumenten weiter.quelle
Wenn Sie verstehen, sind
partial
Sie auf halbem Weg. Die Idee vonpartial
ist, Argumente auf eine Funktion vorab anzuwenden und eine neue Funktion zurückzugeben, die nur die verbleibenden Argumente will. Wenn diese neue Funktion aufgerufen wird, enthält sie die vorinstallierten Argumente sowie alle Argumente, die ihr zur Verfügung gestellt wurden.In Clojure
+
ist eine Funktion, aber die Dinge klar zu machen:Möglicherweise wissen Sie, dass die
inc
Funktion einfach 1 zu der übergebenen Zahl addiert.Lassen Sie es uns selbst bauen mit
partial
:Hier geben wir eine weitere Funktion zurück, die 1 in das erste Argument von geladen hat
add
. Daadd
zwei Argumente benötigtinc
werden, möchte die neue Funktion nur dasb
Argument - nicht 2 Argumente wie zuvor, da 1 bereits teilweise angewendet wurde. Somitpartial
ist ein Werkzeug zum Erstellen neuer Funktionen mit vorgegebenen Standardwerten. Deshalb ordnen Funktionen in einer funktionalen Sprache häufig Argumente von allgemein nach spezifisch. Dies erleichtert die Wiederverwendung solcher Funktionen, aus denen andere Funktionen erstellt werden können.Stellen Sie sich nun vor, die Sprache wäre klug genug, um introspektiv zu verstehen, was
add
zwei Argumente wollte. Wenn wir ein Argument übergeben haben, anstatt es zu verhindern, was ist, wenn die Funktion das Argument teilweise angewendet hat, haben wir es in unserem Namen übergeben und verstanden, dass wir wahrscheinlich beabsichtigten, das andere Argument später bereitzustellen? Wir könnten dann definieren,inc
ohne explizit zu verwendenpartial
.So verhalten sich einige Sprachen. Es ist außerordentlich nützlich, wenn man Funktionen zu größeren Transformationen zusammensetzen möchte. Dies würde zu Wandlern führen.
quelle
Ich fand diesen Artikel und den Artikel, auf den er verweist, nützlich, um das Curry besser zu verstehen: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
Wie die anderen bereits erwähnt haben, ist dies nur eine Möglichkeit, eine Ein-Parameter-Funktion zu haben.
Dies ist insofern nützlich, als Sie nicht davon ausgehen müssen, wie viele Parameter übergeben werden, sodass Sie keine Funktionen mit 2 Parametern, 3 Parametern und 4 Parametern benötigen.
quelle
Wie alle anderen Antworten hilft das Curry, teilweise angewendete Funktionen zu erstellen. Javascript bietet keine native Unterstützung für das automatische Currying. Daher helfen die oben angegebenen Beispiele möglicherweise nicht bei der praktischen Codierung. Es gibt einige hervorragende Beispiele in Livescript (das im Wesentlichen zu js kompiliert wird) http://livescript.net/
Wenn Sie im obigen Beispiel weniger Argumente angegeben haben, generiert Livescript eine neue Curry-Funktion für Sie (doppelt).
quelle
Curry kann Ihren Code vereinfachen. Dies ist einer der Hauptgründe dafür. Beim Currying wird eine Funktion, die n Argumente akzeptiert, in n Funktionen konvertiert, die nur ein Argument akzeptieren.
Das Prinzip besteht darin, die Argumente der übergebenen Funktion unter Verwendung der Closure (Closure) -Eigenschaft zu übergeben, um sie in einer anderen Funktion zu speichern und als Rückgabewert zu behandeln. Diese Funktionen bilden eine Kette, und die endgültigen Argumente werden zur Vervollständigung übergeben die Operation.
Dies hat den Vorteil, dass die Verarbeitung von Parametern vereinfacht werden kann, indem jeweils nur ein Parameter behandelt wird, was auch die Flexibilität und Lesbarkeit des Programms verbessern kann. Dies macht das Programm auch übersichtlicher. Wenn Sie den Code auch in kleinere Teile aufteilen, wird er wiederverwendungsfreundlich.
Zum Beispiel:
Ich kann auch ...
Dies ist sehr gut geeignet, um komplexen Code sauber zu machen und nicht synchronisierte Methoden usw. zu handhaben.
quelle
Eine Curry-Funktion wird auf mehrere Argumentlisten anstatt nur auf eine angewendet.
Hier ist eine reguläre Funktion ohne Curry, die zwei Int-Parameter x und y hinzufügt:
Hier ist eine ähnliche Funktion, die Curry ist. Anstelle einer Liste mit zwei Int-Parametern wenden Sie diese Funktion auf zwei Listen mit jeweils einem Int-Parameter an:
Was hier passiert, ist, dass Sie beim Aufrufen
curriedSum
tatsächlich zwei herkömmliche Funktionsaufrufe hintereinander erhalten. Der erste Funktionsaufruf verwendet einen einzelnen Int-Parameter mit dem Namenx
und gibt einen Funktionswert für die zweite Funktion zurück. Diese zweite Funktion übernimmt den Int-Parametery
.Hier ist eine Funktion mit dem Namen
first
, die im Geiste das tut, was der erste Aufruf einer traditionellen Funktion bewirkencurriedSum
würde:Wenn Sie 1 auf die erste Funktion anwenden, dh die erste Funktion aufrufen und 1 übergeben, erhalten Sie die zweite Funktion:
Das Anwenden von 2 auf die zweite Funktion ergibt das Ergebnis:
quelle
Ein Beispiel für Currying wäre, wenn Sie Funktionen haben, von denen Sie momentan nur einen der Parameter kennen:
Zum Beispiel:
Da Sie den zweiten Parameter für den Rückruf beim Senden nicht kennen,
performAsyncRequest(_:)
müssten Sie hier ein weiteres Lambda / Closure erstellen, um dieses an die Funktion zu senden.quelle
func callback
Rückkehr selbst? Es heißt @callback(str)
solet callback = callback(str)
, Rückruf ist nur der Rückgabewert vonfunc callback
func callback(_:data:)
akzeptiert zwei Parameter, hier gebe ich nur einen, denString
, also wartet er auf den nächsten (NSData
), deshalblet callback
wartet jetzt eine andere Funktion darauf, dass Daten übergeben werdenHier ist das Beispiel einer generischen und der kürzesten Version für das Funktionscurrying mit n-Nr. von params.
quelle
Hier finden Sie eine einfache Erklärung der Curry-Implementierung in C #. In den Kommentaren habe ich versucht zu zeigen, wie nützlich Curry sein kann:
quelle
Currying ist eine der Funktionen höherer Ordnung von Java Script.
Currying ist eine Funktion vieler Argumente, die so umgeschrieben wird, dass sie das erste Argument verwendet und eine Funktion zurückgibt, die wiederum die verbleibenden Argumente verwendet und den Wert zurückgibt.
Verwirrt?
Sehen wir uns ein Beispiel an:
Dies ähnelt der folgenden Curry-Funktion:
Was bedeutet dieser Code?
Lesen Sie nun die Definition noch einmal,
Currying ist eine Funktion vieler Argumente, die so umgeschrieben wird, dass sie das erste Argument verwendet und eine Funktion zurückgibt, die wiederum die verbleibenden Argumente verwendet und den Wert zurückgibt.
Immer noch verwirrt? Lassen Sie mich tief erklären!
Wenn Sie diese Funktion aufrufen,
Es wird Ihnen eine Funktion wie diese zurückgeben,
Dies nennt man also Funktionen höherer Ordnung. Das heißt, wenn Sie eine Funktion nacheinander aufrufen, wird eine andere Funktion zurückgegeben. Dies ist eine genaue Definition für eine Funktion höherer Ordnung. Dies ist der größte Vorteil für die Legende Java Script. Also komm zurück zum Currying,
Diese Zeile übergibt das zweite Argument an die Funktion curryAdd.
was wiederum ergibt,
Ich hoffe, Sie verstehen die Verwendung von Curry hier. Also, zu den Vorteilen kommen,
Warum Curry?
Es nutzt die Wiederverwendbarkeit von Code. Weniger Code, weniger Fehler. Sie fragen sich vielleicht, wie es weniger Code ist?
Ich kann es mit ECMA Script 6 neuen Funktionspfeilfunktionen beweisen.
Ja! ECMA 6 bietet uns die wunderbare Funktion Pfeilfunktionen.
Mit Hilfe der Pfeilfunktion können wir die obige Funktion wie folgt schreiben:
Cool, oder?
Also, weniger Code und weniger Fehler !!
Mit Hilfe dieser Funktion höherer Ordnung kann man leicht einen fehlerfreien Code entwickeln.
Ich fordere dich heraus!
Hoffe, du hast verstanden, was Curry ist. Bitte zögern Sie nicht, hier zu kommentieren, wenn Sie weitere Erläuterungen benötigen.
Danke. Schönen Tag noch!
quelle
Es gibt ein Beispiel für "Currying in ReasonML".
quelle