Zum Inhalt springen

Currying

aus Wikipedia, der freien Enzyklopädie

Currying (vor allem in der Linguistik auch Schönfinkeln) ist die Umwandlung einer Funktion mit mehreren Argumenten in eine Sequenz von Funktionen mit jeweils einem Argument. Obwohl das Verfahren 1924 von Moses Schönfinkel<ref>Moses Schönfinkel: Über die Bausteine der mathematischen Logik. In: Mathematische Annalen 92 (1924). S. 305–316, Digitalisat.</ref> erfunden und von Gottlob Frege<ref>Gottlob Frege: Grundgesetze der Arithmetik. Hermann Pohle, Jena 1893 (Band I) 1903 (Band II) <templatestyles src="Webarchiv/styles.css" />{{#if:20221028150749

      | {{#ifeq: 20221028150749 | *
    | Vorlage:Webarchiv/Wartung/Stern{{#if: korpora.org | {{#invoke:WLink|getEscapedTitle|korpora.org}} | {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/}} }} (Archivversionen)
    | {{#iferror: {{#time: j. F Y|20221028150749}}
         | {{#if:  || }}Vorlage:Webarchiv/Wartung/DatumDer Wert des Parameters {{#if: wayback | wayback | Datum }} muss ein gültiger Zeitstempel der Form YYYYMMDDHHMMSS sein!
         | {{#if: korpora.org | {{#invoke:WLink|getEscapedTitle|korpora.org}} | {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/}} }} {{#ifeq:  | [] | [ | ( }}Memento{{#if: {{#if:  |  |  }} |  des Vorlage:Referrer }} vom {{#time: j. F Y|20221028150749}} im Internet Archive{{#if:  | ;  }}{{#ifeq:  | [] | ] | ) }}
      }}
  }}
      | {{#if:
          | {{#iferror: {{#time: j. F Y|{{{webciteID}}}}}
    | {{#switch: {{#invoke:Str|len|{{{webciteID}}}}}
       | 16= {{#if: korpora.org | {{#invoke:WLink|getEscapedTitle|korpora.org}} | {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/}} }} {{#ifeq:  | [] | [ | ( }}Memento{{#if: {{#if:  |  |  }} |  des Vorlage:Referrer }} vom {{#time: j. F Y| 19700101000000 + {{#expr: floor {{#expr: {{#invoke:Str|sub|{{{webciteID}}}|1|10}}/86400}} }} days}} auf WebCite{{#if:  | ;  }}{{#ifeq:  | [] | ] | ) }}
       | 9 = {{#if: korpora.org | {{#invoke:WLink|getEscapedTitle|korpora.org}} | {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/}} }} {{#ifeq:  | [] | [ | ( }}Memento{{#if: {{#if:  |  |  }} |  des Vorlage:Referrer}} vom {{#time: j. F Y| 19700101000000 + {{#expr: floor {{#expr: {{#invoke:Str|sub|{{#invoke:Expr|base62|{{{webciteID}}}}}|1|10}}/86400}} }} days}} auf WebCite{{#if:  | ;  }}{{#ifeq:  | [] | ] | ) }}
       | #default= Der Wert des Parameters {{#if: webciteID | webciteID | ID }} muss entweder ein Zeitstempel der Form YYYYMMDDHHMMSS oder ein Schüsselwert mit 9 Zeichen oder eine 16-stellige Zahl sein!Vorlage:Webarchiv/Wartung/webcitation{{#if:  || }}
      }}
    | c|{{{webciteID}}}}} {{#if: korpora.org | {{#invoke:WLink|getEscapedTitle|korpora.org}} | {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/}} }} (Memento{{#if: {{#if:  |  |  }} |  des Vorlage:Referrer}} vom {{#time: j. F Y|{{{webciteID}}}}} auf WebCite{{#if:  | ;  }}{{#ifeq:  | [] | ] | ) }}
  }}
          | {{#if: 
              | Vorlage:Webarchiv/Today
              | {{#if:
                      | Vorlage:Webarchiv/Generisch
                      | {{#if: korpora.org | {{#invoke:WLink|getEscapedTitle|korpora.org}} | {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/}} }}  
                 }}}}}}}}{{#if:
    | Vorlage:Webarchiv/archiv-bot
  }}{{#invoke:TemplatePar|check
     |all      = url=
     |opt      = text= wayback= webciteID= archive-is= archive-today= archiv-url= archiv-datum= ()= archiv-bot= format= original=
     |cat      = Wikipedia:Vorlagenfehler/Vorlage:Webarchiv
     |errNS    = 0
     |template = Vorlage:Webarchiv
     |format   = *
     |preview  = 1
  }}{{#ifexpr: {{#if:20221028150749|1|0}}{{#if:|+1}}{{#if:|+1}}{{#if:|+1}}{{#if:|+1}} <> 1
    | {{#if:  || }}Vorlage:Webarchiv/Wartung/Parameter{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Genau einer der Parameter 'wayback', 'webciteID', 'archive-today', 'archive-is' oder 'archiv-url' muss angegeben werden.|1}}
  }}{{#if: 
    | {{#switch: {{#invoke:Webarchiv|getdomain|{{{archiv-url}}}}}
        | web.archive.org = 
          {{#if:  || }}{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Im Parameter 'archiv-url' wurde URL von Internet Archive erkannt, bitte Parameter 'wayback' benutzen.|1}} 
        | webcitation.org = 
          {{#if:  || }}{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Im Parameter 'archiv-url' wurde URL von WebCite erkannt, bitte Parameter 'webciteID' benutzen.|1}} 
        | archive.today |archive.is |archive.ph |archive.fo |archive.li |archive.md |archive.vn = 
          {{#if:  || }}{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Im Parameter 'archiv-url' wurde URL von archive.today erkannt, bitte Parameter 'archive-today' benutzen.|1}}
      }}{{#if: 
         | {{#iferror: {{#iferror:{{#invoke:Vorlage:FormatDate|Execute}}|}}
             | {{#if:  || }}Vorlage:Webarchiv/Wartung/Parameter{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Der Wert des Parameter 'archiv-datum' ist ungültig oder hat ein ungültiges Format.|1}}
          |  }} 
         | {{#if:  || }}Vorlage:Webarchiv/Wartung/Parameter{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Der Pflichtparameter 'archiv-datum' wurde nicht angegeben.|1}}
      }}
    | {{#if: 
         | {{#if:  || }}Vorlage:Webarchiv/Wartung/Parameter{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Der Parameter 'archiv-datum' ist nur in Verbindung mit 'archiv-url' angebbar.|1}}
      }}
  }}{{#if:{{#invoke:URLutil|isHostPathResource|https://korpora.zim.uni-duisburg-essen.de/Frege/}}
    || {{#if:  || }}
  }}{{#if: korpora.org
    | {{#if: {{#invoke:WLink|isBracketedLink|korpora.org}}
        | {{#if:  || }}
      }}
    | {{#if:  || }}Vorlage:Webarchiv/Wartung/Linktext_fehlt
  }}{{#switch: 
    |addlarchives|addlpages= {{#if:  || }}{{#if: 1 |Vorlage:Webarchiv/Wartung/Parameter}}{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: enWP-Wert im Parameter 'format'.|1}}
  }}{{#ifeq: {{#invoke:Str|find|https://korpora.zim.uni-duisburg-essen.de/Frege/%7Carchiv}} |-1
    || {{#ifeq: {{#invoke:Str|find|{{#invoke:Str|cropleft|https://korpora.zim.uni-duisburg-essen.de/Frege/%7C4}}%7Chttp}} |-1
         || {{#switch: {{#invoke:Webarchiv|getdomain|https://korpora.zim.uni-duisburg-essen.de/Frege/ }}
              | abendblatt.de | daserste.ndr.de | inarchive.com | webcitation.org = 
              | #default = {{#if:  || }}{{#if: 1 |Vorlage:Webarchiv/Wartung/URL}}{{#invoke:TemplUtl|failure| Fehler bei Vorlage:Webarchiv: Archiv-URL im Parameter 'url' anstatt URL der Originalquelle. Entferne den vor der Original-URL stehenden Mementobestandteil und setze den Archivierungszeitstempel in den Parameter 'wayback', 'webciteID', 'archive.today' oder 'archive-is' ein, sofern nicht bereits befüllt.|1}}
            }} 
       }}
  }}.</ref> um 1900 vorausgedacht wurde, wird es oft nach Haskell Brooks Curry benannt, der das Verfahren 1958 umfangreich theoretisch ausgearbeitet hat.<ref>Haskell Brooks Curry, Robert Feys, Roger Hindley, Jonathan P. Seldin: Combinatory Logic. North Holland, 2 Bände, 1958, 1972.</ref>

Verfahren

Es sei eine Funktion gegeben, die n Argumente erfordert. Wird diese auf ein Argument angewendet, so konsumiert sie nur genau dieses und liefert als Funktionswert eine weitere Funktion, die noch <math>n-1</math> Argumente verlangt. Die zurückgegebene Funktion wird anschließend auf alle weiteren Argumente angewendet.

In Typen ausgedrückt, handelt es sich um die Umrechnung einer Funktion <math>f \colon A_1\times\ldots\times A_n\to B</math> zu einer modifizierten Funktion {{#if:trim|<math>f_\mathrm{curried} \colon A_1\to(A_2\to( \ldots (A_n\to B) \ldots ))</math>.}}<ref>Dabei bezeichnet <math>(X \to Y)</math> oder <math>[X \to Y]</math> die Menge der Abbildungen von {{#if:trim|<math>X</math> nach <math>Y</math>.}}</ref>

Eine alternative Schreibweise ist {{#if:trim|}} wobei <math>\operatorname{curry}</math> als ein Operator verstanden wird, der <math>n</math>-stellige Abbildungen (für <math>n>1</math>) modifiziert zu einer einstelligen Abbildung, deren Bildwerte einstellige Abbildungen sind usw., wobei der Reihe nach alle Argumente der ursprünglichen Abbildung durchlaufen werden; formal:

{{#if:trim|<math>\operatorname{curry}\colon (A_1\times\ldots\times A_n\to B)\, \to\, (A_1\to(A_2\to( \ldots (A_n\to B) \ldots )))</math>.}}

Das Konzept des Currying ist verwandt mit, aber (für <math>n>2</math>) verschieden von dem der partiellen Anwendung wie etwa:

{{#if:trim|<math>f(a_1, a_2, \ldots a_{n-1},\cdot)\colon A_n \to B, a_n \mapsto f(a_1, a_2, \ldots a_n)</math>,}}
{{#if:trim|<math>f(a_1, \underbraceVorlage:\cdot, \ldots,\cdot_{{(n-1)\text{-mal}}}))\colon A_2\times\ldots\times A_n \to B, (a_2,\dots,a_n) \mapsto f(a_1, a_2, \ldots a_n)</math>.}}

Im einstelligen Fall (<math>n=1</math>) hat Currying keine Auswirkung:

{{#if:trim|}}

im zweistelligen Fall (<math>n=2</math>) besteht der Zusammenhang

{{#if:trim|<math>f_\mathrm{curried}\colon A_1 \to (A_2 \to B), a_1 \mapsto f(a_1, \cdot)</math>,}} d. h. für alle {{#if:trim|<math>a_1 \in A_1</math>:}}
{{#if:trim|}}

im dreistelligen Fall (<math>n=3</math>) gilt für {{#if:trim|<math>a_1 \in A_1</math>:}}

{{#if:trim|<math>f_\mathrm{curried}(a_1)\colon A_2 \to (A_3 \to B), a_2 \mapsto f(a_1, a_2, \cdot)</math>,}} und mit zusätzlich {{#if:trim|<math>a_2 \in A_2</math>:}}
{{#if:trim|<math>f_\mathrm{curried}(a_1)(a_2)\colon A_3 \to B, a_3 \mapsto f(a_1, a_2, \cdot)</math>,}} d. h. {{#if:trim|}}

allgemein:

{{#if:trim|}}
{{#if:trim|}}<ref>Im nullstelligen Fall (n=0) würde das Currying einer Abbildung <math>f</math> ohne Parameter und mit einem Wert <math>b \in B</math> eine einstellige Abbildung mit konstantem Wert <math>b</math> zuordnen, also etwa
{{#if:trim|<math>f_\mathrm{curried} \colon B \to B, x \mapsto b</math>.}}</ref>

Es kommt häufig vor, dass eine mehrstellige Abbildung nicht für alle Wertekombinationen aus den Trägermengen <math>A_1,\dots,A_n</math> definiert ist, also nur auf einer Teilmenge des kartesischen Produkts <math>R = D_f \sube A_1 \times \cdots \times A_n</math>, d. h. auf (dem Graphen einer) Relation.<ref>Ein Beispiel ist <math>f(a_1,a_2) := a_1 / (a_1 - a_2)</math> mit <math>a_1, a_2 \in \R \setminus \Delta_{\R}</math> (wobei <math>\Delta_{\R}</math> die Diagonale <math>\{(a_1,a_2)\in \R^2|a_1=a_2\}</math> bezeichnet).</ref> Man kann diese Situation behandeln, indem man entweder grundsätzlich partielle Abbildungen zulässt und die obigen Definitionen formal übernimmt, oder man dagegen am Konzept totaler Abbildungen festhält; in letzterem Falle werden die Definitionsbereiche der beteiligten Abbildungen von der Wahl bereits festgelegter Parameter abhängig, wie das Beispiel zweistelliger Abbildungen zeigt:

{{#if:trim|}}

der Definitionsbereich dieser Abbildung ist von <math>a_1</math> abhängig:

{{#if:trim|<math>\{a_2 \in A_2}}

also die Urbildfaser von <math>a_1</math> bezüglich des als Relation aufgefassten Definitionsbereichs {{#if:trim|}}<ref>Im obigen Beispiel ist dies <math>\R \setminus \{a_1\}</math>.</ref>

Da für n=1 gilt <math>f_\mathrm{curried} = f</math>, kann für <math>f_\mathrm{curried}</math> dasselbe Symbol verwendet werden wie für <math>f</math>. Man nennt dies Überladung (siehe auch Signatur (Modelltheorie) §Anmerkungen).<ref>Voraussetzung ist, dass das Symbol <math>f</math> nicht schon anderweitig mit Stelligkeit 1 überladen ist (siehe Beispiel unten, dies zwingt zwischen <math>\operatorname{mult}</math> und <math>\operatorname{prod}</math> zu unterscheiden).</ref>

Beispiele

Lambda-Notation

Ein Beispiel in Lambda-Notation soll das Verfahren verdeutlichen, wobei die Funktion konkret folgendermaßen definiert sei:

<math> \lambda x\ y\ z\ .\ x\ y\ z </math>

Die Funktion verlangt also 3 Argumente und gibt diese zurück. Die Definition ist äquivalent zu:

<math> \lambda x.\lambda y.\lambda z\ .\ x\ y\ z </math>

Bei der Anwendung der Funktion auf die Argumente a, b und c geschieht Folgendes:

<math> \left(\lambda x.\lambda y.\lambda z\ .\ x\ y\ z\right)\ a\ b\ c\ \mathsf{-\ Die\ Anwendung} </math>

<math> \left(\lambda y.\lambda z\ .\ a\ y\ z\right)\ b\ c </math>

<math> \left(\lambda z\ .\ a\ b\ z\right)\ c </math>

<math>a\ b\ c\ \mathsf{-\ Resultat}</math>

Nach erstmaliger Anwendung der Funktion auf a, b und c wird x im Funktionskörper durch das erste Argument a ersetzt. Das Resultat ist eine Funktion, die noch die Argumente y und z verlangt. Diese wird sofort auf b und c angewendet.

Überladung

Angenommen, wir haben eine zweistellige Multiplikationsfunktion {{#if:trim|<math>\operatorname{mult}</math>,}} die zwei natürliche Zahlen multipliziert, d. h. einem Paar natürlicher Zahlen ihr Produkt zuordnet:

<math>\operatorname{mult}\colon\, \begin{cases} \N \times \N \to \N \\ (m,n) \mapsto m * n \end{cases}</math> mit <math>\operatorname{mult}(m,n) = m * n</math> <ref>Zur Unterscheidung vom Platzhalter <math>\cdot</math> wird hier <math>*</math> als Multiplikationszeichen verwendet.</ref>

Per Definition wird diese Funktion auf zwei natürliche Zahlen angewendet und eine natürliche Zahl wird zurückgegeben, beispielsweise <math>\operatorname{mult}(2,3) = 6</math>.

Wird nun zunächst das erste Argument besetzt (etwa mit <math>2</math>), das zweite noch freigelassen, entsteht eine einstellige ‚höhere Funktion‘, die selbst ein (weiteres) Argument aufnimmt und das Produkt mit diesem festen Parameter (der Nummer <math>2</math>) zurückgibt:

<math>\operatorname{mult}(2, \cdot)\colon\,</math> <math>\begin{cases} \N \to \N \\ n \mapsto 2 * n \end{cases}</math>,

und für ein beliebiges festes erstes Argument <math>m \in \N</math>:

{{#if:trim|<math>\operatorname{mult}(m, \cdot)\colon\,</math> <math>\begin{cases} \N \to \N \\ n \mapsto m * n \end{cases}\,</math> .}}

Currying bedeutet nun bei einer n-stelligen Funktion, diesen Vorgang so lange durchzuführen, bis nur eine noch einstellige höhere Funktion übrigbleibt. Für n = 2 ist daher:

<math>\operatorname{mult}_\mathrm{curried}\colon\, \begin{cases} \N \to (\N \to \N) \\ m \mapsto \operatorname{mult}(m, \cdot) \end{cases}\,</math> <ref>Dieser Funktion könnte man auch einen eigenen Namen vergeben:
<math>\operatorname{doppelt} := \operatorname{mult}_\mathrm{curried}(2) = \operatorname{mult}(2, \cdot) \colon \N \to \N</math>

mit {{#if:trim|}}</ref> Da die Bezeichnung <math>\operatorname{mult}</math> als einstellige Funktion noch unbesetzt ist, kann diese überladen werden,<ref>Man unterscheide zwischen <math>\operatorname{mult}</math> und der überladenen Funktion <math>\operatorname{prod}</math> mit <math>\operatorname{prod}(k_1,\dotsc,k_r) = \prod_{i=1}^r k_i</math> zur Stelligkeit <math>r</math> und Faktoren {{#if:trim|<math>k_i \in \N</math>.}} Zwar ist zweistellig {{#if:trim|}} aber einstellig ist <math>\operatorname{prod}(m) = m</math>, während <math>\operatorname{mult}(m) = \operatorname{mult}_\mathrm{curried}(m) = \operatorname{mult}(m,\cdot)</math> eine einstellige Funktion ist.</ref> d. h., im einstelligen Fall wird <math>\operatorname{mult}</math> als <math>\operatorname{mult}_\mathrm{curried}</math> verstanden:

{{#if:trim|}}

Geometrisches Beispiel

Datei:Grafico 3d x2+xy+y2.png
f(x, y) = x^2 + x y + y^2

Man kann sich die Situation für eine Funktion mit zwei Argumenten <math>z = f(x, y)</math> wie folgt vorstellen: das Fixieren einer Argumentvariable entspricht einer Einschränkung der zweidimensionalen Definitionsmenge auf eine eindimensionale Teilmenge, z. B. <math>y = 1</math>, die resultierende Funktion entspricht der Schnittkurve des Graphen von <math>f(x,y)</math> mit der Ebene aller Punkte <math>(x, 1, z)</math>. Alle Punkte <math>(x, y, z)</math> des Graphen können somit auch durch eine zweistufige Auswahl erreicht werden: zunächst durch die Festlegung der Schnittebene <math>y = 1</math> und dann durch die Auswertung der Schnittkurve <math>s(x) = f(x, y)|_{y=1}</math> an der Stelle <math>x</math>.

Anwendung

Currying wird überwiegend in Programmiersprachen und Kalkülen verwendet, in denen Funktionen nur ein einzelnes Argument erhalten dürfen. Dazu gehören beispielsweise ML, Unlambda und der Lambda-Kalkül sowie das nach Curry benannte Haskell. Viele dieser Sprachen bieten dem Programmierer allerdings syntaktische Möglichkeiten, dies zu verschleiern. Ein Beispiel hierfür ist die Äquivalenz der Funktionsdefinition im oben gezeigten Beispiel.

JavaScript

Das nachfolgende Beispiel zeigt Currying in JavaScript. Zunächst wird eine Funktion uncurried_add definiert, die als Ergebnis die Summe der beiden Argumente hat. Andererseits wird eine Funktion curried_add definiert, die eine als Closure definierte Funktion zurückgibt, welche partiell angewendet werden kann.

<syntaxhighlight lang="javascript"> function uncurried_add(x, y) {

   return x + y;

}

function curried_add(x) {

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

}

console.log(uncurried_add(3, 5)); // 8 console.log(curried_add(3)(5)); // 8

const add_three = curried_add(3); console.log(add_three(5)); // 8 console.log(add_three(12)); // 15 </syntaxhighlight>

Durch Currying wird die Funktion partiell angewendet, wobei die Funktionsargumente nacheinander übergeben werden und zwischenzeitlich in einer neuen Funktion gehalten werden, die beliebig weiterverwendet werden kann.

Die Funktionen können in JavaScript mit der Lambda-Notation auch kürzer definiert werden: <syntaxhighlight lang="javascript"> const uncurried_add = (x, y) => x + y; const curried_add = x => y => x + y; </syntaxhighlight>Geläufig ist in JavaScript auch das Currying durch apply, eine Methode des Prototyps von Funktionen, der ein Kontextobjekt und eine Teilmenge der Parameter übergeben werden. Das Kontextobjekt kann dabei null oder undefined sein und wird dann implizit durch das globale Objekt ersetzt:<ref>{{#invoke:Vorlage:Literatur|f}}</ref><syntaxhighlight lang="javascript"> function uncurried_add(x, y) {

   return x + y;

}

const curried_add = uncurried_add.bind(null, 3);

console.log(curried_add(5)); // 8 </syntaxhighlight>

Java

<syntaxhighlight lang="java"> import java.util.function.*;

class Main {

   static IntBinaryOperator uncurriedAdd = (x, y) -> x + y;
   static IntFunction<IntUnaryOperator> curriedAdd = x -> y -> x + y;
   public static void main(String[] args) {
       System.out.println(uncurriedAdd.applyAsInt(3, 5)); // 8
       System.out.println(curriedAdd.apply(3).applyAsInt(5)); // 8
       var addThree = curriedAdd.apply(3);
       System.out.println(addThree.applyAsInt(5)); // 8
       System.out.println(addThree.applyAsInt(12)); // 15
   }

} </syntaxhighlight>

Kotlin

<syntaxhighlight lang="kotlin"> val uncurried_add = { x: Int, y: Int -> x + y } val curried_add = { x: Int -> { y: Int -> x + y } }

println(uncurried_add(3, 5)) // 8 println(curried_add(3)(5)) // 8

val add_three = curried_add(3) println(add_three(5)) // 8 println(add_three(12)) // 15 </syntaxhighlight>

C++

C++ führte den Lambda-Kalkül mit anonymen Funktionen in die Sprache ein. Mit dem Schlüsselwort auto wird durch Typinferenz der Datentyp implizit abgeleitet, ohne den Datentypen explizit deklarieren zu müssen. Dadurch ergibt sich eine kürzere Schreibweise für die Currifizierung:<syntaxhighlight lang="c++">

  1. include <iostream>

using namespace std;

int uncurried_add(int x, int y) {

   return x + y;

}

auto curried_add(int x) {

   return [x](int y) { return x + y; };

}

int main() {

   cout << uncurried_add(3, 5) << endl; // 8
   cout << curried_add(3)(5) << endl; // 8
   auto add_three = curried_add(3);
   cout << add_three(5) << endl; // 8
   cout << add_three(12) << endl; // 15
   return 0;

} </syntaxhighlight>

Man beachte, dass die Erwähnung des Typs int im Argument des Lambda-Ausdrucks auch durch auto ersetzt werden kann, wodurch die Implementierung verallgemeinert wird.

C

Da es in der Programmiersprache C keine anonymen Funktionen gibt, wird eine benannte Funktion add separat definiert, die von curried_add zurückgegeben wird. Der Wert von x wird in der globalen Variablen z gespeichert, da die Funktion add nicht auf die Continuation der Funktion curried_add zugreifen kann.<syntaxhighlight lang="c">

  1. include <stdio.h>

int uncurried_add(int x, int y) {

   return x + y;

}

int z;

int add(int y) {

   return y + z;

}

typedef int function(int);

function* curried_add(int x) {

   z = x;
   return add;

}

int main() {

   printf("%d\n", uncurried_add(3, 5)); // 8
   printf("%d\n", curried_add(3)(5)); // 8
   function* add_three = curried_add(3);
   printf("%d\n", add_three(5)); // 8
   printf("%d\n", add_three(12)); // 15
   return 0;

} </syntaxhighlight>

C#

<syntaxhighlight lang="c#"> using System;

class Program {

   delegate int Method(int x, int y);
   delegate Func<int, int> Curry(int x);
   static Method uncurried_add = (x, y) => x + y;
   static Curry curried_add = x => y => x + y;
   public static void Main() {
       Console.WriteLine(uncurried_add(3, 5)); // 8
       Console.WriteLine(curried_add(3)(5)); // 8
       var add_three = curried_add(3);
       Console.WriteLine(add_three(5)); // 8
       Console.WriteLine(add_three(12)); // 15
   }

} </syntaxhighlight>

F#

<syntaxhighlight lang="fsharp"> let uncurried_add (x, y) = x + y let curried_add x y = x + y

printfn "%i" (uncurried_add (3, 5)) // 8 printfn "%i" ((curried_add 3) 5) // 8 printfn "%i" (curried_add 3 5) // 8

let add_three = curried_add 3 printfn "%i" (add_three 5) // 8 printfn "%i" (add_three 12) // 15 </syntaxhighlight>

Go

<syntaxhighlight lang="golang"> package main

import "fmt"

var uncurried_add = func(a, b int) int { return a + b }

var curried_add = func(a int) func(a int) int { return func(b int) int { return a + b } }

func main() {

fmt.Println(uncurried_add(2, 3)) fmt.Println(curried_add(2)(3))

addThree := curried_add(3) fmt.Println(addThree(5)) // 8 fmt.Println(addThree(12)) // 15 } </syntaxhighlight>

Haskell

In der Programmiersprache Haskell kann eine Funktion nur genau einen Parameter haben. Wenn man eine Funktion mit mehreren Argumenten aufrufen möchte, müssen die Argumente zuerst in einem neuen Objekt zusammengesetzt werden, sodass die Funktion nur ein Argument erhält. Dafür können die Parameter in runden Klammern mit Kommata getrennt aufgelistet werden, um ein Tupel zu definieren.<syntaxhighlight lang="haskell"> uncurried_add (x, y) = x + y </syntaxhighlight>Eine Alternative dazu ist das Currying. In der expliziten Schreibweise definiert man für jeden Wert im Tupel jeweils eine Funktion mit nur einem Argument. Solange noch nicht alle Argumente übergeben wurden, wird eine Funktion zurückgegeben, die ein Teilergebnis liefert.<syntaxhighlight lang="haskell"> curried_add x = \y -> x + y </syntaxhighlight>Da die Schreibweise mit mehreren Lambda-Funktionen umständlich sein kann, gibt es eine syntaktisch gezuckerte Notation, die semantisch äquivalent ist. Schreibt man die Argumente ohne runde Klammern hintereinander, erhält man automatisch eine currifizierte Funktion.

<syntaxhighlight lang="haskell"> curried_add x y = x + y </syntaxhighlight>Die currifizierte Funktion kann sowohl explizit als auch implizit partiell angewendet werden.<syntaxhighlight lang="haskell"> main = do

   print (uncurried_add (3, 5)) -- 8
   print ((curried_add 3) 5) -- 8
   print (curried_add 3 5) -- 8
   let add_three = curried_add 3
   print (add_three 5) -- 8
   print (add_three 12) -- 15

</syntaxhighlight>Zudem gibt es in Haskell die Möglichkeit eine Funktion im Nachhinein zwischen currifizierter und nicht currifizierter Definition umzuwandeln. Dafür werden die Funktionen curry und uncurry verwendet.<syntaxhighlight lang="haskell"> main = do

   let uncurried = uncurry curried_add
   print (uncurried (3, 5)) -- 8
   let curried = curry uncurried_add
   print ((curried 3) 5) -- 8
   print (curried 3 5) -- 8
   let add_three = curried 3
   print (add_three 5) -- 8
   print (add_three 12) -- 15

</syntaxhighlight>

Python

<syntaxhighlight lang="python"> def uncurried_add(x, y):

   return x + y

def curried_add(x):

   return lambda y: x + y

print(uncurried_add(3, 5)) # 8 print(curried_add(3)(5)) # 8

add_three = curried_add(3) print(add_three(5)) # 8 print(add_three(12)) # 15 </syntaxhighlight>

Raku

<syntaxhighlight lang="raku"> sub uncurried_add($x, $y) { $x + $y }

sub curried_add($x) {

   sub ($y) { $x + $y };

}

say uncurried_add(3, 5); # 8 say curried_add(3)(5); # 8

my &add_three = &curried_add(3); say &add_three(5); # 8 say &add_three(12); # 15 </syntaxhighlight>Es gibt in der Programmiersprache Raku die Möglichkeit, ein Funktionsobjekt erst beim Funktionsaufruf zu currifizieren.<syntaxhighlight lang="raku"> my &uncurried_add = sub ($x, $y) { $x + $y }; say &uncurried_add(3, 5); # 8 say &uncurried_add.assuming(3)(5); # 8

my &add_three = &uncurried_add.assuming(3); say &add_three(5); # 8 say &add_three(12); # 15 </syntaxhighlight>

Ruby

<syntaxhighlight lang="ruby"> def uncurried_add(x, y)

   return x + y

end

def curried_add(x)

   return lambda { |y| x + y }

end

puts uncurried_add(3, 5) # 8 puts curried_add(3).call(5) # 8

add_three = curried_add(3) puts add_three.call(5) # 8 puts add_three.call(12) # 15 </syntaxhighlight>Es gibt in der Programmiersprache Ruby die Möglichkeit, ein Funktionsobjekt erst beim Funktionsaufruf zu currifizieren.<syntaxhighlight lang="ruby"> uncurried_add = lambda { |x, y| x + y } puts uncurried_add.call(3, 5) # 8 puts uncurried_add.curry[3][5] # 8

add_three = uncurried_add.curry[3] puts add_three.call(5) # 8 puts add_three.call(12) # 15 </syntaxhighlight>

Scheme

<syntaxhighlight lang="scheme"> (define uncurried-add (lambda (x y)

   (+ x y)))

(define curried-add (lambda (x)

   (lambda (y)
       (+ x y))))

(display (uncurried-add 3 5)) (newline) ; 8 (display ((curried-add 3) 5)) (newline) ; 8

(define add-three (curried-add 3))

(display (add-three 5)) (newline) ; 8 (display (add-three 12)) (newline) ; 15 </syntaxhighlight>

Tcl

In Tcl ist es nicht notwendig, irgendwelche speziellen Konstrukte als curried- oder uncurried-Variante vorzubereiten.

Ein Kommando-Aufruf ist in Tcl nur eine Liste von Worten, in der das Kommando-Wort an erster Position steht. Mit dem Operator {*} kann man ein Argument, das seinerseits eine Liste ist, inplace durch deren Elemente ersetzen. Damit kann eine beim Aufruf an vorderster Position stehende Liste neben dem zu rufenden Kommando zusätzlich beliebig viele Argumente in sich tragen.

Currying ist demzufolge identisch mit dem Anhängen eines weiteren Wortes an diese Liste, und jeder mit {*} beginnende Aufruf ist ein Lambda-Call (Benannt nach den in anderen Sprachen oft „Lambda-Ausdruck“ genannten anonymen Funktionen, die sich gut auf diese Weise einbinden lassen).

Zum Addieren ist hier das Standard-Kommando tcl::mathop::+ verwendet, das zur Implementierung der hier nicht benutzten Tcl-Expression-Syntax existiert. Dieses Kommando addiert beliebig viele Argumente.

Da man solche Experimente sinnvollerweise in der Tcl-Konsole anstellt, sind hier keine expliziten print-Anweisungen nötig. <syntaxhighlight lang="tcl"> tcl::mathop::+ 3 5  ;# 8 direkter Aufruf

set f tcl::mathop::+  ;# simple "Lambda"-Liste, nur das Kommando {*}$f 3 5  ;# 8 Aufruf über "Lambda" in Variable f

lappend f 3  ;# "Currying" durch Hinzufügen set f {tcl::mathop::+ 3}  ;# "Curried" alternativ direkt formuliert {*}$f 5  ;# 8 Aufruf über "Curried Lambda"

lappend f 1 2  ;# mehr Parameter hinzufügen {*}$f 4 5  ;# 15 = (3+1+2) + (4+5) ... ganz natürlich </syntaxhighlight>

Delphi

<syntaxhighlight lang="delphi"> program curried;

{$APPTYPE CONSOLE}

{$R *.res}

uses

 System.SysUtils;

function uncurried_add(a, b: Integer): Integer; begin

 Result := a + b;

end;

function curried_add(a: Integer): TFunc<Integer, Integer>; begin

 Result := function(b: Integer): Integer
   begin
     Result := a + b;
   end;

end;

begin

 Writeln(uncurried_add(3, 5)); // 8
 Writeln(curried_add(3)(5)); // 8
 var addThree := curried_add(3);
 Writeln(addThree(5)); // 8
 Writeln(addThree(12)); //15

end. </syntaxhighlight>

Einzelnachweise und Anmerkungen

<references />