Frage

ich ziemlich oft sehen im Internet verschiedene Beschwerden, dass andere Völker Beispiele für currying sind nicht anzubiedern, sind aber tatsächlich nur teilweise Anwendung.

Ich habe nicht eine anständige Erklärung dessen, was teilweise Anwendung ist, oder wie es sich von currying gefunden. Es scheint eine allgemeine Verwirrung, mit gleichwertigen Beispielen sein wird als currying an einigen Stellen beschrieben und teilweise Anwendung in anderen.

Könnte jemand geben mir eine Definition der beiden Begriffe und Einzelheiten darüber, wie sie sich unterscheiden?

War es hilfreich?

Lösung

Currying wird die Umwandlung eine einzige Funktion von n Argumenten in n Funktionen mit einem einzigen Argumente jedem. Angesichts der folgenden Funktion:

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

Wenn curried 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 dies tun:

f(x)(y)(z);

Viele funktionale Sprachen können Sie f x y z schreiben. Wenn Sie nur f x y anrufen oder f (x) (y) dann erhalten Sie einen teilweise angewandt funktions des Rückgabewert eine Schließung von lambda(z){z(x(y))} mit gebenen in den Werten von x und y f(x,y) ist.

Eine Möglichkeit, Teil Anwendung zu verwenden ist Funktionen als Teil-Anwendungen allgemeiner Funktionen zu definieren, wie faltet :

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

Andere Tipps

Der einfachste Weg, um zu sehen, wie sie sich unterscheiden ist ein reales Beispiel zu betrachten. Nehmen wir an, dass wir eine Funktion Add haben, die zwei Zahlen als Eingabe und gibt eine Zahl als Ausgabe, zum Beispiel Add(7, 5) kehrt 12. In diesem Fall:

  • Partial Anwendung die Funktion Add mit einem Wert 7 werden uns eine neue Funktion als Ausgabe. Diese Funktion selbst dauert 1 Nummer als Eingabe und gibt eine Zahl ein. Wie zum Beispiel:

    Partial(Add, 7); // returns a function f2 as output
    
                     // f2 takes 1 number as input and returns a number as output
    

    So können wir dies tun:

    f2 = Partial(Add, 7);
    f2(5); // returns 12;
           // f2(7)(5) is just a syntactic shortcut
    
  • Currying die Funktion Add wird uns eine neue Funktion als Ausgabe. Diese Funktion selbst dauert 1 Nummer als Ein- und Ausgänge noch eine weitere neue Funktion. Diese dritte Funktion nimmt dann 1 Zahl als Eingabe und gibt eine Zahl als Ausgabe. Wie zum Beispiel:

    Curry(Add); // returns a function f2 as output
    
                // f2 takes 1 number as input and returns a function f3 as output
                // i.e. f2(number) = f3
    
                // f3 takes 1 number as input and returns a number as output
                // i.e. f3(number) = number
    

    So können wir dies tun:

    f2 = Curry(Add);
    f3 = f2(7);
    f3(5); // returns 12
    

Mit anderen Worten, „currying“ und „teilweise Anwendung“ sind zwei völlig unterschiedliche Funktionen. Currying dauert genau 1 eingegeben wird, wohingegen teilweise Anwendung dauert 2 (oder mehr) Eingänge.

Auch wenn sie beide eine Funktion als Ausgang zurückkehren, sind die zurückgegebenen Funktionen ganz andere Formen, wie oben gezeigt.

Hinweis: Dies wurde von F # Basics einen hervorragenden Einführungsartikel für .NET-Entwickler Nummer abrufen in der funktionalen Programmierung.

  

Currying bedeutet eine Funktion mit vielen Argumenten in eine Reihe zu brechen   von Funktionen, die jeweils ein Argument nehmen und schließlich produzieren die   gleiches Ergebnis wie die ursprüngliche Funktion. Currying ist wahrscheinlich der   für Entwickler neuen funktionale Programmierung herausforderndes Thema, vor allem, weil es   wird oft mit teilweise Anwendung verwechselt. Sie können sowohl bei der Arbeit   in diesem Beispiel:

let multiply x y = x * y    
let double = multiply 2
let ten = double 5
     

Gleich, sollten Sie Verhalten sehen, die von den meisten unterscheidet   imperativen Sprachen. Die zweite Anweisung erstellt eine neue Funktion   genannte Doppel durch ein Argument an eine Funktion, die zwei übernimmt.   Das Ergebnis ist eine Funktion, die ein int Argument annimmt und ergibt die   gleiche Leistung wie wenn Sie multiplizieren mit x gleich 2 und y genannt hatten   gleich das Argument. In Bezug auf Verhalten, es ist das gleiche wie die   Code:

let double2 z = multiply 2 z
     

Oft sagen die Leute fälschlicherweise, dass mehrfach curried ist doppelt zu bilden.   Aber das ist nur etwas wahr. Die Multiplikationsfunktion ist curried, aber   das geschieht, wenn sie definiert ist, da die Funktionen in F # curried durch   Standard. Wenn die Doppelfunktion erstellt wird, ist es genauer zu   sagen, dass die Multiplikationsfunktion teilweise angewandt wird.

     

Die Multiplikationsfunktion ist wirklich eine Reihe von zwei Funktionen. Der Erste   Funktion nimmt einen int Argument und gibt eine weitere Funktion,   effektiv Bindung x auf einen bestimmten Wert. Diese Funktion übernimmt auch   ein int-Argument, das man sich denken kann als der Wert y zu binden. Nach   Diese zweite Funktion, x und y Aufruf beide gebunden sind, so ist das Ergebnis   das Produkt von x und y, wie in dem Körper des Doppels definiert.

     

Um eine doppelte, die erste Funktion in der Kette von mehrfach zu erstellen   Funktionen ausgewertet mehrfach teilweise zu übernehmen. die daraus resultierende   Funktion wird den Namen doppelt gegeben. Wenn doppelt ausgewertet, verwendet es   ihr Argument zusammen mit dem teilweise angewandt Wert der zu schaffen,   Ergebnis.

Interessante Frage. Nach ein bisschen suchen, „Partial Funktion Anwendung ist nicht anzubiedern“ die beste Erklärung gab ich gefunden. Ich kann nicht sagen, dass die praktische Unterschied zu mir besonders offensichtlich, aber dann bin ich kein Experte FP ...

Eine weitere nützliche aussehende Seite (die ich bekenne, dass ich noch nicht vollständig gelesen) ist "Currying und Partial-Anwendung mit Java Closures" .

Es ist wie folgt aussehen ist weit verwirrt Begriffspaar wohlgemerkt.

Ich habe dies in einem anderen Thread https://stackoverflow.com/a/12846865/1685865 . Kurz gesagt, Teilfunktion Anwendung ist über einige Argumente eines gegebenen Multivariablen-Funktion eine andere Funktion Fixierung mit weniger Argumente zu erhalten, während über Currying ist eine Funktion von n Argumente in eine einstellige Funktion drehen, die eine unäre Funktion gibt ... [Ein Beispiel Currying ist am Ende dieses Beitrags dargestellt.]

Currying ist meist von theoretischem Interesse: man Berechnungen mit nur einstelligen Funktionen ausdrücken kann (d alle Funktion ist einstellige). In der Praxis und als Nebenprodukt, ist es eine Technik, die viele nützliche machen kann (aber nicht alle) teilweise funktionelle Anwendungen trivial, wenn die Sprache curried Funktionen. Auch hier ist es nicht das einzige Mittel Teilanwendungen zu implementieren. So könnte man Szenarien begegnen, wo teilweise Anwendung auf andere Weise geschehen, aber die Leute sind zu verkennen sie als Currying.

(Beispiel für Currying)

In der Praxis würde man nicht nur schreiben

lambda x: lambda y: lambda z: x + y + z

oder das Äquivalent Javascript

function (x) { return function (y){ return function (z){ return x + y + z }}}

statt

lambda x, y, z: x + y + z

im Interesse des Currying.

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

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

Partial-Anwendung ist eine Abhängigkeit von zwei (oder mehr) Argumenten, die eine Funktion f und einer oder mehr zusätzlichen Argumente nehmen eine neue Funktion zu f g und gibt:

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

Die Verwirrung entsteht, weil mit zwei Argumenten Funktion die folgende Gleichung gilt:

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

Beide Seiten werden das gleiche Argument Funktion ergeben.

Die Gleichheit ist für höhere arity Funktionen, da in diesem Fall currying nicht wahr wird wieder eine einargumentigen Funktion, während partielle Anwendung einer mehr Argument Funktion zurück.

Der Unterschied liegt auch im Verhalten, während transformiert die gesamte ursprüngliche Funktion rekursiv currying (einmal für jedes Argument), teilweise Anwendung ist nur ein Schritt ersetzt werden.

. Quelle: Wikipedia Currying

Der Unterschied zwischen Curry und teilweise Anwendung kann am besten durch dieses folgende JavaScript-Beispiel veranschaulicht werden:

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

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

6 === partial(2, 3);

Teil Anwendung ergibt sich in Abhängigkeit von kleineren arity; im obigen Beispiel hat f eine arity von 3 während partial nur eine Stelligkeit 2. Noch wichtiger ist, eine teilweise angewandte Funktion würde geben das Ergebnis sofort invoke auf sein , nicht eine andere Funktion auf der currying Kette. Also, wenn Sie so etwas wie partial(2)(3) sehen, es ist nicht teilweise Anwendung in der Wirklichkeit.

Lesen Sie auch:

Für mich teilweise Anwendung muss eine neue Funktion erstellen, in dem die verwendeten Argumente in die resultierenden Funktion vollständig integriert sind.

Die meisten funktionalen Sprachen implementieren currying durch einen Verschluss der Rückkehr: nicht unter Lambda bewerten, wenn teilweise angewandt. Also, für die partielle Anwendung interessant zu sein, müssen wir einen Unterschied zwischen currying und teilweise Anwendung machen und teilweise Anwendung prüfen, wie und Auswertung unter Lambda currying.

kann ich hier sehr falsch sein, da ich nicht einen starken Hintergrund in der theoretischen Mathematik oder die funktionalen Programmierung, aber von meinem kurzen Ausflug in FP, so scheint es, dass currying eine Funktion von N Argumenten in N Funktionen zu drehen neigt ein Argument, während partielle Anwendung [in der Praxis] funktioniert besser mit variadische Funktionen mit einer unbestimmten Anzahl von Argumenten. Ich weiß, dass einige der Beispiele in früheren Antworten diese Erklärung trotzen, aber es hat mir geholfen, die meisten, um die Konzepte zu trennen. Betrachten Sie dieses Beispiel (geschrieben in Coffeescript für Prägnanz, ich entschuldige mich, wenn es verwirrt weiter, aber bitte fragen Sie nach Klärung, falls erforderlich):

# partial application
partial_apply = (func) ->
  args = [].slice.call arguments, 1
  -> func.apply null, args.concat [].slice.call arguments

sum_variadic = -> [].reduce.call arguments, (acc, num) -> acc + num

add_to_7_and_5 = partial_apply sum_variadic, 7, 5

add_to_7_and_5 10 # returns 22
add_to_7_and_5 10, 11, 12 # returns 45

# currying
curry = (func) ->
  num_args = func.length
  helper = (prev) ->
    ->
      args = prev.concat [].slice.call arguments
      return if args.length < num_args then helper args else func.apply null, args
  helper []

sum_of_three = (x, y, z) -> x + y + z
curried_sum_of_three = curry sum_of_three
curried_sum_of_three 4 # returns a function expecting more arguments
curried_sum_of_three(4)(5) # still returns a function expecting more arguments
curried_sum_of_three(4)(5)(6) # returns 15
curried_sum_of_three 4, 5, 6 # returns 15

Das ist natürlich ein konstruiertes Beispiel, aber feststellen, dass eine Funktion teilweise Anwendung, die eine beliebige Anzahl von Argumenten akzeptiert ermöglicht es uns, eine Funktion auszuführen, aber mit einigen vorläufigen Daten. eine Funktion Currying ähnlich ist, jedoch ermöglicht es uns, eine N-Parameter-Funktion in Stücken, bis zur Ausführung, aber nur, bis alle N-Parameter werden berücksichtigt.

Auch dies ist mein nehmen von den Dingen, die ich gelesen habe. Wenn jemand nicht einverstanden ist, würde ich einen Kommentar, warum nicht eine sofortige Downvote zu schätzen wissen. Auch wenn die Coffee schwer zu lesen, besuchen Sie bitte coffeescript.org, klicken Sie auf „versuchen, Coffeescript“ und in meinem Code und fügen Sie die kompilierte Version zu sehen, die (hoffentlich) mehr Sinn machen. Dank!

Ich hatte eine Menge diese Frage beim Lernen und habe, da es oft gefragt worden. Der einfachste Weg, ich den Unterschied beschreiben kann, ist, dass beide gleich sind :) Lassen Sie mich erklären ... es gibt natürlich Unterschiede.

Beide Teil Anwendung und currying beinhalten Argumente an eine Funktion liefern, vielleicht nicht alle auf einmal. Ein ziemlich kanonisches Beispiel ist das Hinzufügen von zwei Zahlen. In Pseudo-Code (eigentlich JS ohne Schlüsselwörter), kann die Basisfunktion sein, die folgenden:

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

Wenn ich eine „ADDone“ -Funktion wollte, habe ich es teilweise Anwendung finden könnte oder es Curry:

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

Jetzt mit ihnen ist klar:

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

Also, was ist der Unterschied? Nun, es ist subtil, aber teilweise Anwendung beinhaltet einige Argumente liefern und die zurückgegebene Funktion wird dann execute die Hauptfunktion beim nächsten Aufruf während currying warten wird, bis es alle Argumente hat erforderlich:

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 teilweise Anwendung einige Werte prefill, wohl wissend, dass das nächste Mal, wenn Sie die Methode aufrufen, wird ausgeführt, es undefinierte alle unversorgten Argumente verlassen; verwenden currying wenn Sie eine teilweise angewandte Funktion so oft immer wieder zurückzukehren, wie notwendig, 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

Hope, das hilft!

UPDATE: Einige Sprachen oder lib Implementierungen ermöglicht es Ihnen, eine arity (Gesamtzahl der Argumente in Endbewertung) der teilweisen Anwendung Umsetzung passieren, die meine beiden Beschreibungen in ein verwirrendes Durcheinander conflate kann ... aber an diesem Punkt, der zwei Techniken sind weitgehend austauschbar.

Einfache Antwort

Curry: können Sie eine Funktion aufrufen, es in mehreren Anrufen Aufspalten und bietet ein Argument pro Anruf

.

Partial:. können Sie eine Funktion aufrufen, es in mehrere Anrufe Aufspalten mehrere Argumente pro Anruf Bereitstellung


Einfache Hinweise

Beide ermöglichen es Ihnen, eine Funktion weniger Argumente Bereitstellung zu nennen (oder, besser, sofern sie kumulativ). Tatsächlich beide binden (bei jedem Aufruf) einen bestimmten Wert auf bestimmte Argumente der Funktion.

Der wirkliche Unterschied gesehen werden kann, wenn die Funktion von mehr als 2 Argumente hat.


Einfach e (c) (Probe)

(in Javascript)

function process(context, success_callback, error_callback, subject) {...}

warum vorbei immer die Argumente, wie Kontext und die Rückrufe, wenn sie immer das gleiche sein werden? bindet nur einige Werte für die Funktion

processSubject = _.partial(process, my_context, my_success, my_error)

und ruft es auf Subject1 und foobar mit

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

Bequemer ist es nicht?

Es gibt auch andere tolle Antworten hier, aber ich glaube, dieses Beispiel (nach meinem Verständnis) in Java von Vorteile für einige Leute sein könnte:

public static <A,B,X> Function< B, X > partiallyApply( BiFunction< A, B, X > aBiFunction, A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< X > partiallyApply( Function< A, X > aFunction, A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  A, Function< B, X >  > curry( BiFunction< A, B, X > bif ){
    return a -> partiallyApply( bif, a );
}

So currying gibt Ihnen eine einargumentigen Funktion Funktionen zu erstellen, in denen Teil Anwendung eine Wrapper-Funktion erstellt, dass harte Codes ein oder mehr Argumente.

Wenn Sie kopieren und einfügen möchten, die folgende ist lautere aber freundlicher, mit zu arbeiten, da die Typen sind nachsichtiger:

public static <A,B,X> Function< ? super B, ? extends X > partiallyApply( final BiFunction< ? super A, ? super B, X > aBiFunction, final A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< ? extends X > partiallyApply( final Function< ? super A, X > aFunction, final A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  ? super A,  Function< ? super B, ? extends X >  > curry( final BiFunction< ? super A, ? super B, ? extends X > bif ){
    return a -> partiallyApply( bif, a );
}

In diesem Schreiben, verwirrte ich currying und uncurrying. Sie sind inverse Transformationen auf Funktionen. Es spielt wirklich keine Rolle, was Sie nennen, die, so lange wie Sie bekommen, was die Transformation und ihre Inverse darstellen.

Uncurrying ist nicht sehr klar definiert (oder besser gesagt, gibt es „widersprüchlichen“ Definitionen, die alle den Geist der Idee erfassen). Grundsätzlich bedeutet es eine Funktion drehen, die mehrere Argumente in eine Funktion verwendet, die ein einziges Argument annimmt. Zum Beispiel:

(+) :: Int -> Int -> Int

Nun, wie macht man das in eine Funktion, die ein einziges Argument? Sie betrügen, natürlich!

plus :: (Int, Int) -> Int

Beachten Sie, dass Plus nimmt jetzt ein einziges Argument (das aus zwei Dingen). Super!

Was ist der Sinn davon? Nun, wenn Sie eine Funktion, die zwei Argumente übernimmt, und Sie haben ein paar Argumente, es ist schön zu wissen, dass Sie die Funktion auf die Argumente anwenden können, und noch bekommen, was Sie erwarten. Und in der Tat, die sanitären Anlagen bereits vorhanden ist zu tun, so dass Sie müssen nicht Dinge tun, wie explizites Pattern-Matching. Alles, was Sie tun müssen, ist:

(uncurry (+)) (1,2)

Was ist also Teilfunktion Anwendung? Es ist eine andere Art und Weise eine Funktion in zwei Argumente in eine Funktion mit einem Argument zu drehen. Es funktioniert jedoch anders. Auch hier wollen wir (+) nehmen als Beispiel. Wie könnten wir es in eine Funktion drehen, die einen einzelnen Int als Argument? Wir betrügen!

((+) 0) :: Int -> Int

Das ist die Funktion, die Null zu jedem Int erstellt.

((+) 1) :: Int -> Int

addiert 1 zu jedem Int. Usw. In jedem dieser Fälle (+) wird als „teilweise angewandt“.

Ich werde die meisten Menschen annehmen, die diese Frage stellen mit den grundlegenden Konzepten vertraut sind, so sie keine Notwendigkeit, darüber zu sprechen ist. Es ist die Überlappung, die der verwirrende Teil ist.

Das könnte Sie möglich ist, die Konzepte zu benutzen, aber Sie verstehen sie zusammen als diese pseudo-Atom-amorphe konzeptionelle Unschärfe. Was fehlt, ist zu wissen, wo die Grenze zwischen ihnen ist.

Statt zu definieren, was jeder ist, dann ist es einfacher, nur ihre Unterschiede-die Grenze zu markieren.

Currying ist, wenn Sie auf definieren die Funktion.

Partial Application ist, wenn Sie auf Anruf die Funktion.

Anwendung ist Mathe-sprechen für eine Funktion aufrufen.

Partial Anwendung erfordert eine curried Funktion aufrufen und eine Funktion als Rückgabetyp zu bekommen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top