Während sich die meisten Besucher der Uphill Conf 2019 bereits auf das Apéro einstimmten, betrat Anjana Vakil die Gurtenbühne. Und das ausgerechnet mit dem „definitv nutzlosesten Talk“ der Konferenz. Ausgehend vom Lamdba-Kalkül zeigte sie, wie man nur mit Funktionen Zahlen, Kontroll- und Datenstrukturen entwickeln kann. Das sollte man eigentlich nicht tun, es macht aber ziemlich viel Spass. Und ich denke, dass es Sinn macht, sich auf die Grundlagen der funktionalen Programmierung zurück zu besinnen…

Das Lamdba-Kalkül ist ein mathematischer Formalismus, welcher einzig auf Abstraktionen (Funktionen) und deren Applikation beruht [1]. Er wurde in den 1930er Jahren von Alonzo Church entwickelt. Interessanterweise war Church der Doktorvator von Alan Turing und sie haben gemeinsam die Church-Turing-These entwickelt, welche ungefähr folgendes besagt:
Jedes berechenbare Problem kann sowohl mit einer Turing Maschine als auch mit dem Lambda-Kalkül gelöst werden.
Syntax | Name | Beschreibung |
x | Variable | Ein Bezeichner für einen Parameter oder einen mathematischen Wert. |
(ƛx.M) | Abstraktion | Eine Funktionsdefinition. Die Variable x wird gebunden. |
(M N) | Applikation | Applikation eines Argumentes auf eine Funktion. |
(ƛx.x+1)
ƛ
gefolgt von genau einem Argument, hier x
(dies kann aber ein beliebiger Bezeichner sein). Nach dem Argument trennt ein Punkt .
den Funktionsrumpf ab, in diesem Fall x+1
.x
durch den Wert des Arguments ersetzt (2). Wenn dies für alle Argumente durchgespielt wurde, kann der Funktionsrumpf evaluiert werden (3) und wir erhalten das Resultat (4).(ƛx.x+1) (ƛx.x+1) 5 (1) (ƛ5.5+1) (2) (ƛ5.6) (3) 6 (4)
ƛ == =>
ƛ
nicht zur Verfügung, stattdessen können wir mit ES6 auf Arrow Functions zurück greifen. Folgende Tabelle zeigt einige Beispiele von Funktionsdefinitionen in Lambda-Kalkül, ES6 und ES5:Name | Lambda | ES6 | ES5 |
Identity |
ƛx.x |
x => x |
function(x) {return x} |
Increment |
ƛx.x+1 |
x => x + 1 |
function(x) {return x + 1} |
Add |
ƛx.ƛy.x+y |
x => y => x + y |
function(x) { return function(y) { return x + y } } |
Functional Booleans
if-else
. Ausgehend vom „Ternary Operator“ können wir eine Signatur einer Funktion ifThenElse
einfach ableiten, wobei jedes Element, also auch
, zu einem Argument der Funktion ifThenElse
wird:<bool> ? <then do this> : <else do this>
const ifThenElse => bool => thendothis => elsedothat => // ????
bool
kann nur eine Funktion oder ein Wert sein. Da wir aber keine Booleans zur Verfügung haben, müssen wir uns dies zuerst verdienen und True
und False
als Funktionen (troo und faals, da true und false reservierte Wörter sind) definieren. In obiger Definition von ifThenElse
können wir bool
als Funktion betrachten, welche entscheidet, ob wir das erste Argument (thn
) oder das zweite (els
) anwenden sollen. Dementsprechend können wir eine „boolsche Funktion“ als Auswahl aus zwei Argumenten definieren, wobei eine Funktion troo
das erste Argument zurück geben soll und faals
das zweite:const troo = thn => els => thn; // return the first argument, drop the second const faals = thn => els => els; // return the second argument, drop the first
ifThenElse
: Wähle aus zwischen dem ersten oder dem zweiten Argument. Und weil ifThenElse
eine derartige Funktion und zwei weitere Werte erhält, können wir einfach diese Funktion auf diese zwei Werte anwenden:const ifThenElse = bool => thn => els => bool(thn)(els); // bool is a function! not a value!
not
,and
und or
kommt, kann man mit Hilfe der Slides bzw. der Aufzeichnung des Talks von Anjana Vakil nachvollziehen.