Skip to content

Instantly share code, notes, and snippets.

@sma
Last active September 27, 2015 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sma/65fe71a2a8c98d5324b0 to your computer and use it in GitHub Desktop.
Save sma/65fe71a2a8c98d5324b0 to your computer and use it in GitHub Desktop.
es gibt nicht nur keine if-schleife, sondern auch keine while-schleife und keine if-anweisung

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment