Der lambdafizierter Taschenrechner

Beschreibung

Für ein Einstieg-Projekt, um sich am beste einmal mit den Kombinatoren und den Church-Zahlen auseinander zusetzen, haben wir uns für einen Taschenrechner entschieden.

Kern des Taschenrechner

Die Idee war einen Taschenrechner so zu bauen, der möglichst leicht zu bedienen und verständlich aufgebaut ist. Um diese Anforderungen zu erreichen sollte eine einfache Verkettung der arithmetischen Zahlen und Operationen möglich sein.
Als Helferfunktion wurde eine sogenannter CalculatorHandler entwickelt, mit dem solch eine Konstruktion schlussendlich möglich ist.
CaluclatorHandler Implementation:
const calculatorHandler = op => n => k => f => f(op(n)(k));
Der calculatorHandler nimmt jeweils eine arithmetische Operation (Addition, Subtraktion, Multiplikation usw.), zwei Werte und zum Schluss eine Funktion entgegen.

Rechnen mit JavaScript-Zahlen

Um mit JavaScript-Zahlen zu rechnen werden die Arithmetischen-Operatoren von JavaScript benötigt:
const plus = n => k => n + k;
const multiplication = n => k => n * k;
const subtraction = n => k => n - k;
const exponentiation = n => k => n ** k;
const division = n => k => n / k;
// example
plus(1)(2) // 3
multiplication(2)(3) // 6
subtraction(5)(2) // 3
Mit dem CalculatorHandler und den JavaScript-Operatoren kombiniert, werden via Point-Freestyle neue (Calculator-)Funktionen erstellt:
const add = calculatorHandler(plus);
const multi = calculatorHandler(multiplication);
const sub = calculatorHandler(subtraction);
const pow = calculatorHandler(exponentiation);
const div = calculatorHandler(division);
Mit der Thrush-Funktion (T = x => f => f(x) ) als den Taschenrechner-Starter und den neuen CalculatorFunktionen, ist es mögliche eine unendliche Verkettungen von Zahlen und Operationen zu erstellen.
Beispiel:
T(1)(add)(2)(pow)(6)(sub)(2)(div)(8)(add)(7)(multi)(4)(sub)...
Um dieser Verkettung ein Ende zu setzen und das Resultat der Berechnung zu erhalten, benötigt es jeglich die Identitäts-Funktion als Letztes anzuwenden.
Beispiel:
T(1)(add)(2)(id) // 3
T(1)(sub)(2)(id) // -1
T(5)(multi)(4)(add)(2)(id) // 22
T(5)(div)(5)(multi)(100)(add)(1)(id) // 101
Um die Leserlichkeit des Code zu verbessern, wird für die Trush- und id-Funktion ein passender Variablename gewählt.
Implementation (Umbenennung):
const calc = T;
const result = id;
Beispiel:
calc(5)(multi)(4)(sub)(4)(pow)(2)(div)(8)(add)(10)(result) // 42

Rechnen mit Church Encodings-Zahlen

Das der Taschenrechner nicht nur mit JavaScript-Zahlen sondern auch mit Church-Zahlen rechnen kann, braucht es nur die lambdafizierte Arithmetik-Operatoren mit Church-Zahlen mit dem CalculatorHandler zu kombinieren.
Implementationen:
const churchAdd = calculatorHandler(churchAddition);
const churchMulti = calculatorHandler(churchMultiplication);
const churchPow = calculatorHandler(churchPotency);
const churchSub = calculatorHandler(churchSubtraction);
Mit diesen lambdafizierte Arithmetik-Operatoren und den Church-Zahlen lässt sich der Taschenrechner gleich bequem bedienen.
Beispiel:
calc(n5)(churchMulti)(n9)(churchAdd)(n4)(churchSub)(n7)(result) // 42

Die Probleme mit den Church-Zahlen

Negative Zahle

Was der lambdafizierter Taschenrechner im vergleich zum JavaScript-Taschenrechner nicht kann sind mit negative Zahlen rechnen, da Church-Zahlen nur Werte der Natürlichen-Zahlen repräsentiert werden kann:
calc(1)(sub)(7)(result) // -6
calc(n1)(churchSub)(n7)(result) // 0 bzw. n0

Division

Gleiches Problem wie mit den negativen Zahlen, können die Church-Zahlen keine Rationale-Zahlen repräsentiere. Deswegen gibt es keinen lambdafizierten Division-Operator.

Maximum call stack size exceeded

Bei Berechnung mit grösseren Church-Zahlen und längerer Verkettungen kann es zu einem Maximum call stack size exceeded - Error kommen:
calc(n5)(cpow)(n8)(cmulti)(n6)(cadd)(n8)(csub)(n9) ... // Maximum call stack size exceeded

Taschenrechner User-Interface

Um den lambdafizierten Taschenrechner, wie ein gewöhnter Taschenrechner auch visuell bedienen zu können, wurde eine statische HTML-Webseite, mit einem grafischen Taschenrechner und den von hier gezeigten Funktionen implementiert:
Link zum lambdafizierten Taschenrechner: Calculator.html

Eigenschaften des lambdafizierter Taschenrechner

  • Alle Funktionen sind rein
  • In allen Funktionen gibt es keine Ausdrücke wie for, while oder do Schleifen.