In Perl gibt es keine nativen Generatoren wie in Python, aber man kann lazy Evaluation und Iteratoren mit Closures, Statusverfolgung in lexikalischen Variablen und Generatorfunktionen umsetzen:
sub counter { my $x = shift; return sub { return $x++; }; } my $it = counter(5); print $it->(), ", ", $it->(); # 5, 6
Für komplizierte Iteratoren werden häufig CPAN-Module (Iterator::Simple, List::Gen) verwendet. Ein klassisches lazy Muster ist die Rückgabe einer anonymen Unterprogramm mit gespeichertem Zustand.
Nachteile: Es gibt keine integrierte Unterstützung für yield, vielen CPAN-Modulen fehlt die Komponierbarkeit. Rekursion ist auch durch die Stack-Größen begrenzt.
Kann man eine unendliche lazy Liste von Fibonacci-Zahlen in Perl ohne Speicherüberlauf implementieren?
Antwort: Ja, mit Hilfe von Closures:
sub fibonacci { my ($a, $b) = (0, 1); return sub { ($a, $b) = ($b, $a+$b); return $a; }; } my $fib = fibonacci(); print $fib->(), ", ", $fib->(), ", ", $fib->();
Aber wenn man die Ergebnisse in ein Array speichert, wird es mit der Zeit den Speicher überlaufen (d.h. tatsächlich ist nur der Generator selbst „lazy“).
Geschichte
In einem Projekt wurde ein eigener Iterator zur Durchsuchung einer riesigen Datei implementiert, der durch ein Array innerhalb eines Objekts realisiert wurde. Der Iterator ladete die gesamte Datei in den Speicher – und mit wachsender Datei begann der Dienst OOM aufzurufen, wenn mehrere Instanzen arbeiteten.
Geschichte
Ein Closure-Generator für eine Reihe von Details zu einem Bericht führte zu einem unerwarteten Speicherleck – innerhalb des Closures wurde versehentlich eine Referenz auf ein großes Array von Eingabedaten gehalten, was es dem Garbage Collector unmöglich machte, zu arbeiten.
Geschichte
Der Versuch, einen komplexen Generator mittels Rekursion ohne Tiefenverfolgung zu implementieren, führte zu einer Überschreitung des Stack-Limits bei der Verarbeitung von tatsächlich großen Daten, anstelle des erwarteten „lazy“ Durchlaufs.