Lazy Evaluation (verzögerte Auswertung)
Kurz: Bei Lazy Evaluation wird ein Ausdruck erst ausgewertet, wenn sein Ergebnis wirklich gebraucht wird – und dann höchstens einmal. Das Gegenteil ist die sofortige (eager) Auswertung.
Genauer: Dadurch lassen sich unendliche Folgen beschreiben und teure Berechnungen vermeiden, die nie benötigt werden. Haskell ist durchgehend lazy; in anderen Sprachen gibt es Generatoren, Streams, lazy-Variablen und Kurzschluss-Operatoren.
Im Detail
def zahlen(): # Generator: liefert Werte bei Bedarf
n = 1
while True:
yield n
n += 1
from itertools import islice
quadrate = (x * x for x in zahlen() if x % 2 == 1) # Generatorausdruck, nichts berechnet
print(list(islice(quadrate, 5))) # [1, 9, 25, 49, 81]naturalZahlen = [1 ..] -- unendliche Liste
print (take 5 (filter even naturalZahlen)) -- [2,4,6,8,10]val teuer by lazy { println("berechne"); 42 } // erst beim ersten Zugrifffunction* fib() { let [a, b] = [0, 1]; while (true) { yield a; [a, b] = [b, a + b]; } }
const erste = [];
for (const f of fib()) { if (f > 50) break; erste.push(f); }
console.log(erste);Kurzschluss-Auswertung
a && b und a || b werten b nur aus, wenn nötig: if (x != null && x.laenge > 3) ist deshalb sicher.
Vor- und Nachteile
| Vorteile | Nachteile |
|---|---|
| unendliche Datenstrukturen | schwer vorhersagbarer Speicherbedarf (angesammelte Thunks) |
| Arbeit nur bei Bedarf | Debugging und Ausführungsreihenfolge sind weniger offensichtlich |
| elegante Pipelines | Nebenwirkungen erscheinen zu unerwarteten Zeitpunkten |
Lazy Evaluation passt am besten zu reinen Funktionen. Verwandt sind Iteratoren, die Elemente einzeln liefern.
Siehe auch: Iterator, Pure Function, Memoization, Higher-Order-Funktion