Beim Currying wird eine einzelne Funktion von n Argumenten in n Funktionen mit jeweils einem Argument umgewandelt. Gegeben die folgende Funktion:
function f(x,y,z) { z(x(y));}
Wenn Curry, wird:
function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }
Um die vollständige Anwendung von f (x, y, z) zu erhalten, müssen Sie Folgendes tun:
f(x)(y)(z);
In vielen funktionalen Sprachen können Sie schreiben f x y z
. Wenn Sie nur f x y
oder f (x) (y) aufrufen, erhalten Sie eine teilweise angewendete Funktion - der Rückgabewert ist ein Abschluss von lambda(z){z(x(y))}
mit übergebenen Werten von x und y an f(x,y)
.
Eine Möglichkeit , Teil Anwendung zu verwenden ist Funktionen als Teil-Anwendungen allgemeiner Funktionen zu definieren, wie Falte :
function fold(combineFunction, accumulator, list) {/* ... */}
function sum = curry(fold)(lambda(accum,e){e+accum}))(0);
function length = curry(fold)(lambda(accum,_){1+accum})(empty-list);
function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);
/* ... */
@list = [1, 2, 3, 4]
sum(list) //returns 10
@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}
f(0,list) //returns 10
@g = f(0) //same as sum
g(list) //returns 10
Der einfachste Weg, um zu sehen, wie sie sich unterscheiden, besteht darin, ein reales Beispiel zu betrachten . Nehmen wir an, wir haben eine Funktion,
Add
die 2 Zahlen als Eingabe verwendet und eine Zahl als AusgabeAdd(7, 5)
zurückgibt , z12
. B. return . In diesem Fall:Teilweise Anwendung der Funktion
Add
mit einem Wert erhalten7
wir eine neue Funktion als Ausgabe. Diese Funktion selbst nimmt 1 Nummer als Eingabe und gibt eine Nummer aus. So wie:Also können wir das tun:
Durch Currying der Funktion erhalten
Add
wir eine neue Funktion als Ausgabe. Diese Funktion selbst nimmt 1 Nummer als Eingabe und gibt eine weitere neue Funktion aus. Diese dritte Funktion nimmt dann 1 Zahl als Eingabe und gibt eine Zahl als Ausgabe zurück. So wie:Also können wir das tun:
Mit anderen Worten, "Currying" und "Teilanwendung" sind zwei völlig unterschiedliche Funktionen. Currying benötigt genau 1 Eingabe, während Teilanwendung 2 (oder mehr) Eingaben benötigt.
Obwohl beide eine Funktion als Ausgabe zurückgeben, haben die zurückgegebenen Funktionen, wie oben gezeigt, völlig unterschiedliche Formen.
quelle
n-ary
bis(x - n)-ary
, Curry vonn-ary
bisn * 1-ary
. Eine teilweise angewendete Funktion hat einen reduzierten Anwendungsbereich, das heißt, sieAdd7
ist weniger aussagekräftig alsAdd
. Eine Curry-Funktion ist dagegen genauso ausdrucksstark wie die ursprüngliche Funktion.f2(7)(5) is just a syntactic shortcut
? (Ich weiß sehr wenig.) Enthältf2
/ "weiß nicht über" 7 noch nicht?curry
irgendwo eine Implementierung (glaube nicht, dass es in istfunctools
)Hinweis: Dies wurde aus F # Basics übernommen einem hervorragenden Einführungsartikel für .NET-Entwickler, die sich mit funktionaler Programmierung befassen.
quelle
Interessante Frage. Nach einigem Suchen gab "Partial Function Application is currying" die beste Erklärung, die ich gefunden habe. Ich kann das nicht praktisch sagen Unterschied für mich besonders offensichtlich ist, aber dann bin ich kein FP-Experte ...
Eine weitere nützlich aussehende Seite (von der ich gestehe, dass ich sie noch nicht vollständig gelesen habe) ist "Currying and Partial Application with Java Closures" .
Es sieht so aus, als wäre dies ein weit verbreitetes Begriffspaar, wohlgemerkt.
quelle
Ich habe dies in einem anderen Thread https://stackoverflow.com/a/12846865/1685865 beantwortet . Kurz gesagt, bei der Anwendung von Teilfunktionen geht es darum, einige Argumente einer bestimmten multivariablen Funktion zu korrigieren, um eine andere Funktion mit weniger Argumenten zu erhalten, während beim Currying eine Funktion von N Argumenten in eine unäre Funktion umgewandelt wird, die eine unäre Funktion zurückgibt ... [Ein Beispiel für Currying wird am Ende dieses Beitrags gezeigt.]
Currying ist meistens von theoretischem Interesse: Man kann Berechnungen nur mit unären Funktionen ausdrücken (dh jede Funktion ist unär). In der Praxis und als Nebenprodukt ist es eine Technik, die viele nützliche (aber nicht alle) teilweise funktionale Anwendungen trivial machen kann, wenn die Sprache Curry-Funktionen hat. Auch hier ist es nicht das einzige Mittel, Teilanwendungen zu implementieren. Sie könnten also auf Szenarien stoßen, in denen die teilweise Anwendung auf andere Weise erfolgt, die Leute sie jedoch als Currying verwechseln.
(Beispiel Currying)
In der Praxis würde man nicht nur schreiben
oder das entsprechende Javascript
anstatt
um des Currying willen.
quelle
Currying ist eine Funktion eines Arguments, das eine Funktion übernimmt
f
und eine neue Funktion zurückgibth
. Beachten Sie, dassh
ein Argument aus nimmtX
und gibt eine Funktion , die KartenY
zuZ
:Teilanwendung ist eine Funktion von zwei (oder mehr) Argumenten, die eine Funktion
f
und ein oder mehrere zusätzliche Argumente fürf
eine neue Funktion übernimmt und diese zurückgibtg
:Die Verwirrung entsteht, weil bei einer Funktion mit zwei Argumenten die folgende Gleichheit gilt:
Beide Seiten ergeben dieselbe Funktion mit einem Argument.
Die Gleichheit gilt nicht für Funktionen mit höherer Arität, da in diesem Fall beim Currying eine Funktion mit einem Argument zurückgegeben wird, während bei einer Teilanwendung eine Funktion mit mehreren Argumenten zurückgegeben wird.
Der Unterschied liegt auch im Verhalten, während das Currying die gesamte ursprüngliche Funktion rekursiv transformiert (einmal für jedes Argument), ist die teilweise Anwendung nur eine Ersetzung in einem Schritt.
Quelle: Wikipedia Currying .
quelle
Der Unterschied zwischen Curry und Teilanwendung lässt sich am besten anhand des folgenden JavaScript-Beispiels veranschaulichen:
Eine teilweise Anwendung führt zu einer Funktion kleinerer Arität; hat im obigen Beispiel
f
eine Arität von 3, währendpartial
nur eine Arität von 2 vorliegt. Noch wichtiger ist, dass eine teilweise angewendete Funktion das Ergebnis sofort beim Aufrufen zurückgibt, nicht eine andere Funktion in der Currykette. Also, wenn Sie so etwas sehenpartial(2)(3)
, ist es in Wirklichkeit keine teilweise Anwendung.Weiterführende Literatur:
quelle
Einfache Antwort
Curry: Mit dieser Funktion können Sie eine Funktion aufrufen, in mehrere Aufrufe aufteilen und pro Aufruf ein Argument angeben.
Teilweise: Ermöglicht das Aufrufen einer Funktion, das Aufteilen in mehrere Aufrufe und das Bereitstellen mehrerer Argumente pro Aufruf.
Einfache Hinweise
Mit beiden können Sie eine Funktion aufrufen, die weniger Argumente liefert (oder besser kumulativ). Tatsächlich binden beide (bei jedem Aufruf) einen bestimmten Wert an bestimmte Argumente der Funktion.
Der wirkliche Unterschied kann gesehen werden, wenn die Funktion mehr als 2 Argumente hat.
Einfaches e (c) (Probe)
(in Javascript)
Warum immer die Argumente wie Kontext und Rückrufe übergeben, wenn sie immer gleich sind? Binden Sie einfach einige Werte für die Funktion
und nenne es auf subject1 und foobar mit
Bequem, nicht wahr? 😉
Beim Currying müssten Sie jedes Mal ein Argument übergeben
Haftungsausschluss
Ich habe alle akademischen / mathematischen Erklärungen übersprungen. Weil ich es nicht weiß. Vielleicht hat es geholfen 🙃
quelle
Ich hatte diese Frage beim Lernen oft und wurde seitdem oft gestellt. Der einfachste Weg, den Unterschied zu beschreiben, ist, dass beide gleich sind :) Lassen Sie mich erklären ... es gibt offensichtlich Unterschiede.
Sowohl bei der teilweisen Anwendung als auch beim Currying werden Argumente für eine Funktion bereitgestellt, möglicherweise nicht alle auf einmal. Ein ziemlich kanonisches Beispiel ist das Hinzufügen von zwei Zahlen. Im Pseudocode (tatsächlich JS ohne Schlüsselwörter) kann die Basisfunktion die folgende sein:
Wenn ich eine "addOne" -Funktion wollte, könnte ich sie teilweise anwenden oder curry:
Jetzt ist es klar, sie zu benutzen:
Was ist der Unterschied? Nun, es ist subtil, aber eine teilweise Anwendung beinhaltet die Angabe einiger Argumente, und die zurückgegebene Funktion führt dann beim nächsten Aufruf die Hauptfunktion aus, während das Currying so lange wartet, bis alle erforderlichen Argumente vorhanden sind:
Kurz gesagt, verwenden Sie eine Teilanwendung, um einige Werte vorab auszufüllen. Beachten Sie dabei, dass die Methode beim nächsten Aufruf ausgeführt wird und alle nicht bereitgestellten Argumente undefiniert bleiben. Verwenden Sie Currying, wenn Sie eine teilweise angewendete Funktion so oft wie nötig kontinuierlich zurückgeben möchten, um die Funktionssignatur zu erfüllen. Ein letztes erfundenes Beispiel:
Hoffe das hilft!
UPDATE: Einige Sprachen oder lib-Implementierungen ermöglichen es Ihnen, eine Arität (Gesamtzahl der Argumente in der endgültigen Bewertung) an die teilweise Anwendungsimplementierung zu übergeben, die meine beiden Beschreibungen zu einem verwirrenden Durcheinander zusammenführen kann ... aber an diesem Punkt sind die beiden Techniken weitgehend austauschbar.
quelle
Für mich muss die Teilanwendung eine neue Funktion erstellen, bei der die verwendeten Argumente vollständig in die resultierende Funktion integriert sind.
Die meisten funktionalen Sprachen implementieren Currying durch Rückgabe eines Verschlusses: Bei teilweiser Anwendung nicht unter Lambda auswerten. Damit eine teilweise Anwendung interessant ist, müssen wir einen Unterschied zwischen Curry und teilweiser Anwendung machen und die teilweise Anwendung als Curry plus Bewertung unter Lambda betrachten.
quelle
Ich könnte mich hier sehr irren, da ich keinen starken Hintergrund in theoretischer Mathematik oder funktionaler Programmierung habe, aber von meinem kurzen Streifzug durch FP scheint es, dass Currying dazu neigt, eine Funktion von N Argumenten in N Funktionen eines Arguments umzuwandeln. wohingegen eine teilweise Anwendung [in der Praxis] bei variadischen Funktionen mit einer unbestimmten Anzahl von Argumenten besser funktioniert. Ich weiß, dass einige der Beispiele in früheren Antworten dieser Erklärung widersprechen, aber es hat mir am meisten geholfen, die Konzepte zu trennen. Betrachten Sie dieses Beispiel (aus Gründen der Prägnanz in CoffeeScript geschrieben, ich entschuldige mich, wenn es weiter verwirrt, aber bitte bei Bedarf um Klarstellung):
Dies ist offensichtlich ein erfundenes Beispiel, aber beachten Sie, dass das teilweise Anwenden einer Funktion, die eine beliebige Anzahl von Argumenten akzeptiert, es uns ermöglicht, eine Funktion auszuführen, jedoch mit einigen vorläufigen Daten. Das Currying einer Funktion ist ähnlich, ermöglicht es uns jedoch, eine N-Parameter-Funktion in Teilen auszuführen, bis, aber nur bis alle N Parameter berücksichtigt sind.
Auch dies ist meine Einstellung zu Dingen, die ich gelesen habe. Wenn jemand anderer Meinung ist, würde ich mich über einen Kommentar zum Warum und nicht über eine sofortige Ablehnung freuen. Wenn das CoffeeScript schwer zu lesen ist, besuchen Sie bitte coffeescript.org, klicken Sie auf "try coffeescript" und fügen Sie meinen Code ein, um die kompilierte Version anzuzeigen, die (hoffentlich) sinnvoller sein kann. Vielen Dank!
quelle
Ich gehe davon aus, dass die meisten Leute, die diese Frage stellen, bereits mit den Grundkonzepten vertraut sind, sodass sie nicht darüber sprechen müssen. Es ist die Überlappung, die den verwirrenden Teil ausmacht.
Möglicherweise können Sie die Konzepte vollständig nutzen, aber Sie verstehen sie zusammen als diese pseudoatomare amorphe konzeptuelle Unschärfe. Was fehlt, ist zu wissen, wo die Grenze zwischen ihnen liegt.
Anstatt zu definieren, was jeder ist, ist es einfacher, nur ihre Unterschiede hervorzuheben - die Grenze.
Currying ist, wenn Sie die Funktion definieren .
Teilanwendung ist, wenn Sie die Funktion aufrufen .
Die Anwendung ist mathematisch gesprochen, um eine Funktion aufzurufen.
Für eine teilweise Anwendung muss eine Curry-Funktion aufgerufen und eine Funktion als Rückgabetyp abgerufen werden.
quelle
Es gibt hier andere gute Antworten, aber ich glaube, dass dieses Beispiel (nach meinem Verständnis) in Java für einige Leute von Nutzen sein könnte:
Beim Currying erhalten Sie eine Funktion mit einem Argument zum Erstellen von Funktionen, bei der die Teilanwendung eine Wrapper-Funktion erstellt, die ein oder mehrere Argumente fest codiert.
Wenn Sie kopieren und einfügen möchten, ist das Folgende lauter, aber benutzerfreundlicher, da die Typen milder sind:
quelle
Beim Schreiben habe ich Currying und Uncurrying verwechselt. Sie sind inverse Transformationen von Funktionen. Es ist wirklich egal, wie du was nennst, solange du bekommst, was die Transformation und ihre Umkehrung darstellen.
Uncurrying ist nicht sehr klar definiert (oder vielmehr gibt es "widersprüchliche" Definitionen, die alle den Geist der Idee erfassen). Grundsätzlich bedeutet dies, eine Funktion, die mehrere Argumente akzeptiert, in eine Funktion umzuwandeln, die ein einzelnes Argument akzeptiert. Zum Beispiel,
Wie verwandeln Sie dies in eine Funktion, die ein einziges Argument akzeptiert? Du betrügst natürlich!
Beachten Sie, dass plus jetzt ein einziges Argument benötigt (das aus zwei Dingen besteht). Super!
Was ist der Sinn davon? Wenn Sie eine Funktion haben, die zwei Argumente akzeptiert, und Sie haben zwei Argumente, ist es schön zu wissen, dass Sie die Funktion auf die Argumente anwenden können und trotzdem das bekommen, was Sie erwarten. Tatsächlich ist die Installation bereits vorhanden, sodass Sie keine expliziten Mustervergleiche durchführen müssen. Alles was du tun musst, ist:
Was ist also eine Teilfunktionsanwendung? Es ist eine andere Möglichkeit, eine Funktion in zwei Argumenten in eine Funktion mit einem Argument umzuwandeln. Es funktioniert jedoch anders. Nehmen wir noch einmal (+) als Beispiel. Wie können wir daraus eine Funktion machen, die ein einzelnes Int als Argument verwendet? Wir betrügen!
Das ist die Funktion, die jedem Int Null hinzufügt.
addiert 1 zu jedem Int. In jedem dieser Fälle wird (+) "teilweise angewendet".
quelle