Begriff
Currying
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Du hast eine Funktion add(a, b).
Du rufst sie auf: add(2, 3). Ergebnis 5.
Beim Currying (benannt nach Haskell Curry) zerhackst du die Funktion.
Statt einer Funktion, die zwei Dinge nimmt...
Hast du eine Kette von Funktionen, die je ein Ding nehmen.
add(2) gibt eine neue Funktion zurück ("Ich warte auf b").
Diese neue Funktion rufst du mit 3 auf: neueFunktion(3). Ergebnis 5.
Schreibweise: add(2)(3).
Merksatz: Die Transformation einer Funktion mit mehreren Argumenten in eine Kette von Funktionen, die jeweils ein einzelnes Argument akzeptieren.
Warum tun wir uns das an?
Für Wiederverwendbarkeit ("Partial Application").
Angenommen, du hast multiply(a, b).
Du kannst double = multiply(2) erstellen.
Jetzt hast du eine spezialisierte Funktion, die alles verdoppelt. Du musst die 2 nicht jedes Mal neu tippen.
In React (handleChange("email")) oder Redux sieht man das oft.
1. Schönfinkeln
Der deutsche Name (nach Moses Schönfinkel). Klingt lustig, meint das Gleiche.
Mathematisch: f: X x Y -> Z wird zu g: X -> (Y -> Z).
2. Auto-Currying (Haskell)
In Sprachen wie Haskell sind alle Funktionen automatisch gecurryt.
f x y = x + y ist intern immer f = \x -> (\y -> x + y).
Das macht den Code extrem elegant und kompakt (Point-free Style).
1. Lambda Kalkül und mathematische Bindung
Das Konzept des Currying (Schönfinkeln) entspringt nativ dem reinen Lambda-Kalkül (Alonzo Church, 1930er). In dieser fundamentalen Algebra der Logik gibt es per Konstruktion ausschließlich einstellige Funktionen. Ein Ausdruck $\lambda x, y. e$ weicht sofort dem Konstrukt $\lambda x. (\lambda y. e)$. Es bedeutet: Mehrdimensionale Arithmetik (wie f(x,y)) existiert auf Quantenebene in funktionaler Informatik nicht. Alles ist lediglich das Auswerten von Unary-Funktionen und das Zurückliefern (Returnen) von neuen Closure-Objekten im Speicher. Dies untermauert das Theorie-Konstrukt, dass Turingmaschinen exakt die gleiche Ausdruckskraft besitzen wie reines Funktionen-Resolving in Haskell.
2. Typ-Signaturen und Partielle Application in C/C++
In typsicheren abstrakten Sprachen verändert Currying die Signatur des Linkers komplett.
In Haskell sieht man dies an den Pfeilsystematiken: int -> int -> int. Die Rechtsassoziativität bindet den Pfeil als int -> (int -> int). Der Anwender ruft Function(5) auf und die Sprache fabriziert völlig transparent durch Thunks (Speicher-Objekte) eine partiell applizierte Laufzeitversion.
In C++ oder Java ist "echtes" Currying mit immensem Overhead verbunden (mittig über std::bind oder massenhaft Lambdas mit Capture [=]), weil jedes generierte Teil-Ergebnis auf den Heap in std::function Pointern instanziiert werden muss; ein Horror-Szenario für hoch-effiziente CPU-Caches, was es in C-Derivaten aus Hardware-Gründen extrem unbeliebt macht.
3. Point-free Programming (Tacit Programming)
Wer tief in functional Code-Bases arbeitet, stürzt sich wegen Currying auf den Point-free Style.
Anstatt Parameter (die "Points") explizit an Variablen zu nageln, montiert der erfahrene Entwickler Pipelines.
Aus users.filter(u => isAdult(u)).map(u => getName(u)) wird durch die Magie von pipe (oder dem |> Operator) und Currying ein drastisches: pipe(filter(isAdult), map(getName)).
Weil Array-Funktionen curried sind, baut man die Transformer-Kette als reinen Architekturplan "Was passiert", ohne dass die eigentlichen Listendaten je als Iterations-Variablen genannt werden. Das killt Noise-Boilerplate drastisch.
Quick-Check
Gibt es das in Java?
Schwerfällig. Mit Lambdas geht es, sieht aber hässlich aus. Python und JS können es, brauchen aber oft Libraries (Lodash_.curry) oder Arrow-Functionsa => b => a+b.Unterschied zu Partial Application?
Haarspalterei. Currying macht immer 1-Argument-Ketten. Partial Application fixiert einige Argumente (z. B. die ersten 3 von 5) und gibt den Rest zurück. In der Praxis nutzen wir meist Partial Application und nennen es Currying.Performance?
Schlechter. Jeder Funktionsaufruf kostet CPU-Zeit (Stack Frame).add(2,3)ist schneller alsadd(2)(3). Aber wir optimieren auf Lesbarkeit, nicht Nanosekunden.