Die anderen Antworten haben erklärt, was Currying ist: Die Übergabe von weniger Argumenten an eine Curried-Funktion, als sie erwartet, ist kein Fehler, sondern gibt eine Funktion zurück, die den Rest der Argumente erwartet und das gleiche Ergebnis liefert, als wenn Sie alle Argumente auf einmal übergeben hätten.
Ich werde versuchen zu begründen, warum das nützlich ist. Es ist eines dieser Werkzeuge, von denen man nie wusste, dass man sie braucht, bis man sie braucht. Currying ist vor allem ein Weg, um Ihre Programme ausdrucksstärker zu machen - Sie können Operationen mit weniger Code miteinander kombinieren.
Wenn Sie zum Beispiel eine curried-Funktion haben add
können Sie das Äquivalent von JS schreiben x => k + x
(oder Python lambda x: k + x
oder Rubin { |x| k + x }
oder Lisp (lambda (x) (+ k x))
oder ) als nur add(k)
. In Haskelll können Sie sogar den Operator verwenden: (k +)
o (+ k)
(Bei nicht-kommutativen Operatoren kann man mit den beiden Formen in beide Richtungen curryen: (/ 9)
ist eine Funktion, die eine Zahl durch 9 dividiert, was wahrscheinlich der häufigste Anwendungsfall ist, aber es gibt auch (9 /)
für eine Funktion, die 9 durch ihr Argument dividiert). Die Curried-Version ist nicht nur kürzer, sondern enthält auch keine erfundenen Parameternamen wie die x
die in allen anderen Versionen zu finden sind. Das ist nicht nötig. Sie definieren eine Funktion, die eine Konstante k zu einer Zahl addiert, und Sie müssen dieser Zahl keinen Namen geben, nur um über die Funktion zu sprechen. Oder auch nur, um sie zu definieren. Dies ist ein Beispiel für das, was man als "punktfreien Stil" bezeichnet. Sie können Operationen miteinander kombinieren, wenn Sie nichts anderes als die Operationen selbst angeben. Man muss keine anonymen Funktionen deklarieren, die nichts anderes tun, als eine Operation auf ihr Argument anzuwenden, denn *das ist es, was die Operationen bereits sind.
Dies ist sehr praktisch bei Funktionen höherer Ordnung, wenn sie auf eine Curry-freundliche Weise definiert sind. Zum Beispiel kann eine curried map(fn, list)
ermöglicht die Definition eines Mappers mit nur map(fn)
die später auf jede Liste angewendet werden kann. Aber das Currying einer Map, die stattdessen als map(list, fn)
ermöglicht es Ihnen lediglich, eine Funktion zu definieren, die eine andere Funktion auf eine konstante Liste anwendet, was im Allgemeinen wahrscheinlich weniger nützlich ist.
Currying reduziert die Notwendigkeit für Dinge wie Pipes und Threading. In Clojure könnte man eine Temperaturumwandlungsfunktion mit Hilfe des Threading-Makros definieren ->
: (defn f2c (deg) (-> deg (- 32) (* 5) (/ 9))
. Das ist cool, es liest sich schön von links nach rechts ("32 subtrahieren, mit 5 multiplizieren und durch 9 dividieren") und man muss den Parameter nur zweimal statt einmal für jede Unteroperation erwähnen aber es funktioniert nur, weil ->
ist ein Makro, das das gesamte Formular syntaktisch umwandelt, bevor etwas ausgewertet wird. Es verwandelt sich hinter den Kulissen in einen regulären verschachtelten Ausdruck: (/ (* (- deg 32) 5) 9)
. Wenn die mathematischen Operationen kuriert wären, bräuchte man kein Makro, um sie so schön zu kombinieren, wie in Haskell let f2c = (subtract 32) & (* 5) & (/ 9)
. (Obwohl es zugegebenermaßen idiomatischer wäre, die Funktionskomposition zu verwenden, die von rechts nach links gelesen wird: (/ 9) . (* 5) . (subtract 32)
.)
Auch hier ist es schwer, gute Demo-Beispiele zu finden; Currying ist am nützlichsten in komplexen Fällen, in denen es die Lesbarkeit der Lösung wirklich verbessert, aber diese erfordern so viele Erklärungen, nur um das Problem zu verstehen, dass die allgemeine Lektion über Currying im Lärm untergehen kann.
13 Stimmen
[Gemäß der Definition einer kartesischen geschlossenen Kategorie gibt es eine fest Familie von Adjunktionen (natürlich parametrisiert durch A) zwischen X -> X x A und X -> X ^ A. Die Isomorphismen hom(X x A, Y) <-> hom(X, Y^A) sind die
curry
yuncurry
Funktionen von Haskell. Wichtig ist hier, dass diese Isomorphismen von vornherein festgelegt und somit in die Sprache "eingebaut" sind.3 Stimmen
Es gibt ein schönes Tutorial hier für currying in haskell learnyouahaskell.com/higher-order-functions#curried-functions Kurzkommentare sind, dass
add x y = x+y
(curried) ist anders alsadd (x, y)=x+y
(ohne Eile)