Was ist eine reine Funktion?
Vorteile
Die Verwendung reiner Funktionen bietet mehrere Vorteile, sowohl in Bezug auf die Leistung als auch auf die Benutzerfreundlichkeit.
Lesbarkeit
Reine Funktionen sind viel einfacher zu lesen und darüber nachzudenken. Alle relevanten Eingaben und Abhängigkeiten werden als Parameter bereitgestellt, sodass keine Effekte beobachtet werden, die Variablen außerhalb der Eingaben verändern.
Dies bedeutet, dass wir eine Funktion und ihre Abhängigkeiten schnell verstehen können, indem wir einfach die Deklaration der Funktion lesen. Wenn also eine Funktion als f(a, b, c)
deklariert ist, wissen wir, dass nur a
b
und c
Abhängigkeiten von f
.
Portabilität
Da alle Abhängigkeiten als Eingabeparameter bereitgestellt werden und nicht über einen globalen Kontext aufgerufen werden, können diese Abhängigkeiten je nach Kontext, in dem die Funktion aufgerufen wird, vertauscht werden.
Dies bedeutet, dass dieselbe Funktion beispielsweise auf verschiedene Implementierungen derselben Ressource einwirken kann.Dies macht den Code viel portabler und wiederverwendbarer, da dieselbe Funktion in verschiedenen Kontexten verwendet werden kann, anstatt eine andere Funktion schreiben zu müssen, nur um eine andere Implementierung derselben Klasse zu verwenden.Anstatt beispielsweise zwei verschiedene unreine Funktionen schreiben zu müssen, um zwei verschiedene Logger zu verwenden, die global gespeichert sind, würde eine reine Funktion nur den gewünschten Logger als Eingabe aufnehmen.
Testen
Das Fehlen von Nebenwirkungen macht reine Funktionen sehr einfach zu testen, da wir nur testen müssen, ob die Eingaben die gewünschten Ausgaben erzeugen. Wir müssen die Gültigkeit eines globalen Programmstatus in unseren Tests bestimmter Funktionen nicht überprüfen.
Da alle Abhängigkeiten als Eingaben bereitgestellt werden, können wir Abhängigkeiten leicht verspotten. In einer unreinen Umgebung müssten wir den Status einer globalen Abhängigkeit während aller Tests verfolgen.
In einer reinen Umgebung würden wir jedoch einfach alle Abhängigkeiten als Eingabe bereitstellen. Wir müssen uns nicht mehr darum kümmern, den globalen Status während unserer Tests beizubehalten, und wir können jetzt möglicherweise verschiedene Versionen von Abhängigkeiten für verschiedene Tests bereitstellen.
Dies ermöglicht es uns, Funktionen zu testen, während wir explizit die Kontrolle über die bereitgestellten Abhängigkeiten in jedem Test haben.
Referenzielle Transparenz
Referenzielle Transparenz bezieht sich auf die Möglichkeit, den Aufruf einer Funktion durch den entsprechenden Ausgabewert zu ersetzen, ohne das Verhalten eines Programms zu ändern.
Um referenzielle Transparenz zu erreichen, muss eine Funktion rein sein. Dies hat Vorteile in Bezug auf Lesbarkeit und Geschwindigkeit. Compiler sind oft in der Lage, Code zu optimieren, der referenzielle Transparenz aufweist.
Caching
Da reine Funktionen immer dieselbe Ausgabe für dieselbe Eingabe zurückgeben, können wir die Ergebnisse reiner Funktionsaufrufe zwischenspeichern.
Caching bezieht sich auf die Verwendung einer Technik wie Memoization, um die Ergebnisse von Funktionen zu speichern, so dass wir sie nur einmal berechnen müssen.
Normalerweise wird dies für eine Funktion f: Input -> Output
durch eine Map (z. B. eine Hash-Map) von Input -> Output
erreicht.
Beim Ausführen einer Funktion prüfen wir zunächst, ob die Map die Eingabe als Schlüssel enthält. Andernfalls berechnen wir f(input)
und speichern die Ausgabe in der Karte, bevor wir sie zurückgeben.