Sei
name = (x) => ausdruck
eine handlichere Schreibeweise für was in Python
name = lambda x:ausdruck
wäre und was man dort auch als
def name(x): return ausdruck
schreiben könnte.
Dann ist
(x) => ausdruck
eine anonyme Funktion und auch nur ein Ausdruck, d.h. man kann z.B.
(x) => (y) => x + y
schreiben. Dies ist eine Funktion, die eine Funktion liefert, die zu einem übergeben Wert y einen konstanten Wert x addiert, der beim Erzeugen der Funktion (y) => x + y an die äußere Funktion übergeben wurde.
Ach ja, eine anonyme Funktion rufe man (wie in Python) mit () auf, also so:
name(argument)
Ist eine anonyme Funktion nicht an einen Namen gebunden, sieht das so aus:
((x) => (y) => x + y)(1)(2)
Das liefert 3. Alles klar?
Ich behaupte, diese Funktionen reichen aus, um Bedingungen (if
-Anweisungen) und Schleifen (while
-Anweisung) auszudrücken. D.h., ich behaupte, es gibt nicht nur keine if
-Schleifen, sondern auch keine if
-Anweisungen oder while
-Schleifen -- wenigstens konzeptionell nicht.
Definieren wir
true = (x, y) => x()
false = (x, y) => y()
Das sind zwei Funktionen, die jeweils zwei Argumente erwarten und jeweils eines davon als Funktion aufrufen. Was bringen uns diese Funktionen? Sie seien das Ergebnis von z.B. Operationen wie "<", d.h. "3 < 4
" liefere true
und "4 < 3
" liefere false
als Ergebnis. (Den Exkurs, dass 3 < 4
natürlich nur syntaktischer Zucker für <(3, 4)
ist, spare ich mir hier.)
Nun definieren wir noch
if = (x, y, z) => x(y, z)
und schon kann ich damit z.B. die Funktion "min
" wie folgt definieren:
min = (x, y) => if(x < y, () => x, () => y)
Das "() =>
" stört ein bisschen, ist aber notwendig, weil if
zwei Funktionen für y
und z
erwartet und ich daher aus dem "then"- und dem "else"-Fall von "if" erst noch eine (anonyme) Funktion machen muss.
Eine while
-Schleife, die in Python so aussähe
while i < n:
s = s + n
i = i + 1
kann ich wie folgt schreiben:
while(() => i < n, () => s = s + n; i = i + 1)
Ich gönne mir an dieser Stelle noch ";" als Syntax, um einen neuen Ausdruck aus zwei Ausdrücken zu bauen, der das Ergebnis des zweiten Ausdrucks als Wert hat. Somit ist "a ; b
" syntaktischer Zucker für einen Funktionsaufruf ";(a, (_) => b)
" wobei ";
" als "; = (x, y) => y(x)
" definiert ist, aber das nur nebenbei.
Und so sieht dann while
aus:
while = (x, y) => if(x(), () => y(); while(x, y), () => nil)
Will ich auf die "() =>
" verzichten, brauche ich ein etwas anderes Ausführungsmodell.
Ich definiere jetzt, dass wenn ich f(ausdruck1, ausdruck2)
aufrufe, nicht etwa ausdruck1
und ausdruck2
vor dem Funktionsaufruf berechnet werden (wie in Python) sondern erst dann, wenn sie innerhalb von f
das erste Mal benutzt werden. Sie werden quasi unausgewertet an die Funktion übergeben. Werden sie nie benutzt, werden sie auch nie berechnet. Werden sie hingegen mehr als einmal benutzt, werden sie nur das erste mal berechnet, der Wert wird sich gemerkt und dann jedes weitere Mal benutzt. Das nennt man träge Auswertung von Werten und entspricht der Semantik von z.B. Haskell. Ich benötige jetzt auch keinen expliziten Funktionsaufruf, weil ich immer versuche, einen Ausdruck, der noch nicht zu einem Atom, also einen nicht mehr auswertbaren Wert reduziert wurde, auszuwerten. Es reicht, einen Teilausdruck einfach nur zu erwähnen. Er wird dann ausgewertet.
Nun gilt
true = (x, y) => x
false = (x, y) => y
if = (x, y, z) => x(y, z)
while = (x, y) => if(x, y ; while(x, y), nil)
Ich kann auch auf das ",
" verzichten, indem ich mir klarmache, dass das folgendes äquivalent ist:
f = (x, y) => x + y f(1, 2)
f = (x) => (y) => x + y f(1)(2)
Ich kann auf die ()
für einen Funktionsaufruf verzichten, wenn ich weiß, wie viele Argumente jede Funktion benötigt. Das kann ich statisch ermitteln:
f = x => y = > x + y f 1 2
Damit kann ich mein Beispiel wie folgt verkürzen:
true = x => y => x
false = x => y => y
if = x => y => z => x y z
while = x => y => if x y ; while x y nil
Weil das aber jetzt wieder unlesbarer wird, fasse ich x y z => ...
als Kurzform für x => y => z => ...
auf, und entferne einige der =>
wieder:
true = x y => x
false = x y => y
if = x y z => x y z
while = x y => if x y ; while x y nil
Damit kann ich jetzt min
und das while
-Beispiel wie folgt schreiben:
min = x y => if x < y x y
while i < n s += i ; i += 1
Willkommen in der wunderbaren Welt der Funktionen.