Begriff
Functional Programming (FP)
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
OOP baut die Welt aus Dingen (Objekten).
FP baut die Welt aus Aktionen (Funktionen).
Die wichtigste Regel: Keine Nebenwirkungen (Side Effects).
Eine Funktion ist wie eine mathematische Formel: f(x) = x + 1.
Wenn du 5 reinsteckst, kommt IMMER 6 raus.
Die Funktion ändert nichts in der Welt (druckt nichts, speichert nichts in der DB, ändert keine globalen Variablen).
Das macht Programme extrem stabil und testbar.
Merksatz: Ein Programmierparadigma, das Berechnungen als Auswertung mathematischer Funktionen betrachtet und veränderliche Daten (Mutation) sowie Seiteneffekte vermeidet.
Statt Schleifen (for) nutzt man Map, Filter, Reduce.
// Imperativ (Wie mache ich es?)
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] > 10) {
sum += numbers[i];
}
}
// Funktional (Was will ich?)
const sum = numbers
.filter(n => n > 10)
.reduce((acc, n) => acc + n, 0);
Der FP-Code ist kürzer und sagt was passiert, nicht wie.
1. Immutability (Unveränderlichkeit)
In FP ändert man keine Variablen. x = 5; x = 6 ist verboten.
Man erzeugt neue Daten.
const newArr = [...oldArr, 4];
Das verhindert Fehler wie "Wer hat mein Array geändert?!".
Nachteil: Kopieren kostet RAM/CPU.
Lösung: Persistent Data Structures (z. B. Immutable.js). Sie teilen sich den Speicher ("Structural Sharing") und kopieren nur das Nötigste.
2. Higher-Order Functions
Funktionen sind Daten.
Du kannst eine Funktion in eine Variable stecken, sie als Parameter übergeben oder zurückgeben.
const add = (a) => (b) => a + b; (Currying).
add(5)(2) ergibt 7.
Das erlaubt extrem mächtige Komposition ("Baukasten-Prinzip").
3. Monaden (Der Endgegner)
Wie geht man mit Fehlern (null) oder Seiteneffekten (I/O) um, wenn Funktionen "rein" sein müssen?
Man verpackt den Wert in einen Container (Monade).
Maybe(5) oder Nothing.
Man rechnet nur mit dem Container.
"Wenn 5 drin ist, addiere 1. Wenn nichts drin ist, mach nichts."
Das hält die Kern-Logik sauber von if (x == null) Checks.
Wer funktionale Programmierung vertiefen will, findet in Haskell, Lambda Calculus, Currying, Monad und Type Theory die wichtigsten Anschlussbegriffe.
Referential Transparency & Memoization
In FP ist das ultimative Ziel die Referential Transparency. Ein Ausdruck ist "referenziell transparent", wenn er jederzeit im Quellcode durch seinen evaluierten Rückgabewert ersetzt werden kann, ohne das Verhalten der Applikation zu verändern.
Dieses mathematische Prinzip ermöglicht die brutalste Form von Performance-Tuning: Memoization.
Weiß der Compiler durch Stempel wie pure, dass calculateTax(100) absolut immer 119 ergibt (keine API-Calls, kein Zufall, keine State-Reads), kann die Funktion die Eingabe in einem unsichtbaren Dictionary cachen. Beim nächsten Aufruf mit 100 rechnet der CPU überhaupt nicht mehr, sondern zieht reflexartig die 119 aus dem RAM. Reacts useMemo() basiert exakt auf dieser Logik, um teure UI-Rerenders zu killen.
Partial Application und Currying
Funktionale Programmierer brechen Argumente auf (Currying).
Statt fn(x, y, z) machen sie daraus fn(x)(y)(z).
Das klingt irre, hat aber einen Sinn: Partial Application.
Stell dir eine API-Log-Funktion vor: log('error', '[Auth]', 'Bad Login').
Mit FP definierst du den Basis-Context einmal:
const createLogger = (level) => (module) => (msg) => console.log(level, module, msg);
const errorLogger = createLogger('ERROR'); // Fixiertes Level
const authErrorLogger = errorLogger('[Auth]'); // Fixiertes Level + Modul
authErrorLogger('Bad Password'); // Nur noch der variable Teil!
authErrorLogger('Session Expired');
Dadurch baust du dir aus extrem generischen Basis-Funktionen hochspezifische Helfer, ohne Code zu duplizieren.
Kategorie-Theorie: Funktoren und Monaden
Das fundamentale Lego-System der FP ist der Mathematik entliehen (Category Theory).
- Funktor: Ist grob gesagt alles, worauf man
.map()aufrufen kann. (Ein Array, ein Promise). Es ist ein "Container" (Kategorie), den ich öffnen kann, eine Funktion auf den Inhalt anwende, und den transformierten Wert in einem neuen Container desselben Typs verpackt zurückbekomme. - Monade: Ein Funktor auf Steroiden. Wenn du
.map()machst und die darin laufende Funktion selbst wieder ein Array oder einen neuen Container zurückgibt, entsteht eine Verschachtelung wie "Array im Array". Eine Monade erlaubtflatMap()(bind), um den Container flach zu halten, sodass du nicht in der "Callback Hell" der Container landest. JavascriptsPromise.then()ist der bekannteste monadische Operator.
Quick-Check
React und FP?
React liebt FP. UI ist eine Funktion des State:UI = f(State). Komponenten sollten "Pure" sein (gleiche Props -> gleiches HTML). Hooks (useEffect) kapseln die Seiteneffekte.Rekursion?
In reinem FP gibt es keinewhile-Schleifen. Man nutzt Rekursion (Funktion ruft sich selbst auf). Damit der Stack nicht platzt, braucht man "Tail Call Optimization" (TCO), was moderne Compiler können.Referential Transparency?
Du kannst den Funktionsaufrufadd(2,3)überall im Code durch das Ergebnis5ersetzen, ohne dass sich das Programmverhalten ändert.