497 Stimmen

Was ist der Unterschied zwischen Currying und partieller Anwendung?

Ich erlebe im Internet häufig, dass sich andere darüber beschweren, dass ihre Beispiele für das Striegeln gar kein Striegeln sind, sondern nur eine teilweise Anwendung.

Ich habe keine vernünftige Erklärung dafür gefunden, was partielle Anwendung ist oder wie sie sich vom Curry unterscheidet. Es scheint eine allgemeine Verwirrung zu herrschen, wobei gleichwertige Beispiele an einigen Stellen als Currying und an anderen als Partial Application bezeichnet werden.

Könnte mir jemand eine Definition der beiden Begriffe geben und erläutern, wie sie sich unterscheiden?

15voto

Roland Punkte 6970

Currying ist eine Funktion von eine Argument, das eine Funktion f und gibt eine neue Funktion zurück h . Beachten Sie, dass h nimmt ein Argument von X und gibt eine Funktion die Karten Y a Z :

curry(f) = h 
f: (X x Y) -> Z 
h: X -> (Y -> Z)

Die partielle Anwendung ist abhängig von zwei (oder mehr) Argumente, die eine Funktion f und ein oder mehrere zusätzliche Argumente für f und gibt eine neue Funktion zurück g :

part(f, 2) = g
f: (X x Y) -> Z 
g: Y -> Z

Die Verwirrung entsteht, weil bei einer Funktion mit zwei Argumenten die folgende Gleichheit gilt:

partial(f, a) = curry(f)(a)

Beide Seiten ergeben die gleiche Ein-Argument-Funktion.

Die Gleichheit gilt nicht für Funktionen mit höherer Arithmetik, da in diesem Fall Currying eine Ein-Argument-Funktion zurückgibt, während die partielle Anwendung eine Mehr-Argument-Funktion zurückgibt.

Der Unterschied liegt auch im Verhalten: Während Currying die gesamte ursprüngliche Funktion rekursiv umwandelt (einmal für jedes Argument), ist die partielle Anwendung nur eine Ersetzung in einem Schritt.

Quelle: Wikipedia Currying .

12voto

Kamafeather Punkte 6892

Einfache Antwort

Curry: können Sie eine Funktion aufrufen, indem Sie sie in mehrere Aufrufe aufteilen und so eine Argument pro Aufruf.

Teilweise: können Sie eine Funktion aufrufen, indem Sie sie in mehrere Aufrufe aufteilen und so mehrere Argumente pro Anruf.


Einfache Hinweise

Beide ermöglichen es Ihnen, eine Funktion mit weniger Argumenten aufzurufen (oder, besser noch, sie kumulativ bereitzustellen). Eigentlich binden beide (bei jedem Aufruf) einen bestimmten Wert an bestimmte Argumente der Funktion.

Der wirkliche Unterschied zeigt sich, wenn die Funktion mehr als 2 Argumente hat.


Einfach e(c)(Probe)

(in Javascript)

Wir möchten Folgendes durchführen process Funktion auf verschiedenen subject s (z. B. sind unsere Themen "subject1" y "foobar" Zeichenketten):

function process(context, successCallback, errorCallback, subject) {...}

Warum sollten die Argumente, wie Kontext und Rückrufe, immer übergeben werden, wenn sie immer die gleichen sein werden?

Binden Sie einfach einige Werte für die Funktion:

processSubject = _.partial(process, my_context, my_success, my_error)
// assign fixed values to the first 3 arguments of the `process` function

und rufen Sie es auf Thema1 y foobar , wobei die Wiederholung der ersten 3 Argumente weggelassen wird, mit:

processSubject('subject1');
processSubject('foobar');

Gemütlich, nicht wahr?


Mit Striegeln müssen Sie stattdessen ein Argument pro Zeit übergeben

curriedProcess = _.curry(process);   // make the function curry-able
processWithBoundedContext = curriedProcess(my_context);
processWithCallbacks = processWithBoundedContext(my_success)(my_error); // note: these are two sequential calls

result1 = processWithCallbacks('subject1');
// same as: process(my_context, my_success, my_error, 'subject1');

result2 = processWithCallbacks('foobar'); 
// same as: process(my_context, my_success, my_error, 'foobar');

Haftungsausschluss

Ich habe alle akademischen/mathematischen Erklärungen übersprungen. Weil ich sie nicht kenne. Vielleicht hat es geholfen


EDITAR:

Wie hinzugefügt von @basickarl ein weiterer leichter Unterschied in der Verwendung der beiden Funktionen (siehe Lodash für Beispiele) ist das:

  • partial gibt eine vorgekochte Funktion zurück, die kann einmal mit dem/den fehlenden Argument(en) aufgerufen werden und geben das Endergebnis zurück;
  • während curry mehrfach aufgerufen wird (für jedes Argument einmal) und gibt jedes Mal eine vorgefertigte Funktion zurück; mit Ausnahme des Aufrufs mit dem letzten Argument, der das aktuelle Ergebnis der Verarbeitung von todo die Argumente.

Mit ES6:

hier ist ein kurzes Beispiel wie unmittelbar Currying und Partial-Application in ECMAScript 6 sind.

const curriedSum = math => eng => geo => math + eng + geo;
const partialSum = math => (eng, geo) => math + eng + geo;

10voto

gsklee Punkte 4474

Der Unterschied zwischen Curry und partieller Anwendung lässt sich am besten anhand des folgenden JavaScript-Beispiels veranschaulichen:

function f(x, y, z) {
    return x + y + z;
}

var partial = f.bind(null, 1);

6 === partial(2, 3);

Eine Teilanwendung führt zu einer Funktion mit geringerer Arithmetik; im obigen Beispiel, f hat eine Arität von 3, während partial hat nur eine Arität von 2. Noch wichtiger ist, dass eine teilweise angewandte Funktion das Ergebnis sofort nach dem Aufruf zurückgeben und nicht eine andere Funktion weiter unten in der Curry-Kette. Wenn Sie also etwas sehen wie partial(2)(3) ist es in Wirklichkeit keine Teilanwendung.

Lesen Sie weiter:

5voto

sunny-mittal Punkte 467

Diese Frage habe ich mir beim Lernen oft gestellt, und sie wurde mir seitdem auch immer wieder gestellt. Die einfachste Art und Weise, wie ich den Unterschied beschreiben kann, ist, dass beides das Gleiche ist :) Lassen Sie mich das erklären... es gibt natürlich Unterschiede.

Sowohl bei der partiellen Anwendung als auch beim Currying werden Argumente an eine Funktion übergeben, vielleicht nicht alle auf einmal. Ein ziemlich kanonisches Beispiel ist das Addieren zweier Zahlen. In Pseudocode (eigentlich JS ohne Schlüsselwörter) kann die Basisfunktion wie folgt aussehen:

add = (x, y) => x + y

Wenn ich eine "addOne"-Funktion wollte, könnte ich sie teilweise anwenden oder kurieren:

addOneC = curry(add, 1)
addOneP = partial(add, 1)

Jetzt ist ihre Verwendung klar:

addOneC(2) #=> 3
addOneP(2) #=> 3

Worin besteht also der Unterschied? Nun, es ist subtil, aber eine partielle Anwendung beinhaltet die Angabe einiger Argumente und die zurückgegebene Funktion wird dann die Hauptfunktion beim nächsten Aufruf ausführen während Currying so lange warten wird, bis es alle notwendigen Argumente hat:

curriedAdd = curry(add) # notice, no args are provided
addOne = curriedAdd(1) # returns a function that can be used to provide the last argument
addOne(2) #=> returns 3, as we want

partialAdd = partial(add) # no args provided, but this still returns a function
addOne = partialAdd(1) # oops! can only use a partially applied function once, so now we're trying to add one to an undefined value (no second argument), and we get an error

Kurz gesagt, verwenden Sie die partielle Anwendung, um einige Werte vorzufüllen, wobei Sie wissen, dass die Methode beim nächsten Aufruf ausgeführt wird und alle nicht bereitgestellten Argumente undefiniert bleiben; verwenden Sie Currying, wenn Sie eine partiell angewendete Funktion so oft wie nötig zurückgeben wollen, um die Funktionssignatur zu erfüllen. Ein letztes erfundenes Beispiel:

curriedAdd = curry(add)
curriedAdd()()()()()(1)(2) # ugly and dumb, but it works

partialAdd = partial(add)
partialAdd()()()()()(1)(2) # second invocation of those 7 calls fires it off with undefined parameters

Ich hoffe, das hilft!

UPDATE: Einige Sprachen oder Lib-Implementierungen erlauben die Übergabe einer Arität (Gesamtzahl der Argumente in der abschließenden Auswertung) an die Implementierung der Teilanwendung, was meine beiden Beschreibungen in ein verwirrendes Durcheinander verwandeln kann...aber an diesem Punkt sind die beiden Techniken weitgehend austauschbar.

5voto

basickarl Punkte 31184

Viele Leute hier gehen nicht richtig darauf ein, und niemand hat über Überschneidungen gesprochen.

Einfache Antwort

Curling: Ermöglicht den Aufruf einer Funktion, die in mehrere Aufrufe aufgeteilt wird, wobei pro Aufruf ein Argument angegeben wird.

Teilweise Anwendung: Ermöglicht den Aufruf einer Funktion, wobei diese in mehrere Aufrufe aufgeteilt wird und pro Aufruf mehrere Argumente angegeben werden.

Einer der wesentlichen Unterschiede zwischen den beiden ist, dass ein Aufruf einer teilweise angewandte Funktion das Ergebnis sofort zurückgibt und nicht eine andere eine weitere Funktion in der Curry-Kette; dieser Unterschied lässt sich Dieser Unterschied lässt sich bei Funktionen mit einer Arithmetik von mehr als zwei deutlich machen.

Was soll das bedeuten? Das bedeutet, dass es maximal zwei Aufrufe für eine Teilfunktion gibt. Currying hat so viele wie die Anzahl der Argumente. Wenn die Currying-Funktion nur zwei Argumente hat, dann ist sie im Wesentlichen dasselbe wie eine partielle Funktion.

Beispiele

Partielle Anwendung und Currying

function bothPartialAndCurry(firstArgument) {
    return function(secondArgument) {
        return firstArgument + secondArgument;
    }
}

const partialAndCurry = bothPartialAndCurry(1);
const result = partialAndCurry(2);

Teilweise Anwendung

function partialOnly(firstArgument, secondArgument) {
    return function(thirdArgument, fourthArgument, fifthArgument) {
        return firstArgument + secondArgument + thirdArgument + fourthArgument + fifthArgument;
    }
}

const partial = partialOnly(1, 2);
const result = partial(3, 4, 5);

Currying

function curryOnly(firstArgument) {
    return function(secondArgument) {
        return function(thirdArgument) {
            return function(fourthArgument ) {
                return function(fifthArgument) {
                    return firstArgument + secondArgument + thirdArgument + fourthArgument + fifthArgument;
                }
            }
        }
    }
}

const curryFirst = curryOnly(1);
const currySecond = curryFirst(2);
const curryThird = currySecond(3);
const curryFourth = curryThird(4);
const result = curryFourth(5);

// or...

const result = curryOnly(1)(2)(3)(4)(5);

Konventionen zur Namensgebung

Ich werde das schreiben, wenn ich Zeit habe, was bald der Fall sein wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X