En Perl no hay generadores nativos como en Python, pero se pueden implementar cálculos perezosos e iteradores mediante cierres, seguimiento del estado en variables léxicas y funciones generadoras:
sub counter { my $x = shift; return sub { return $x++; }; } my $it = counter(5); print $it->(), ", ", $it->(); # 5, 6
Para iteradores complejos, a menudo se utilizan módulos de CPAN (Iterator::Simple, List::Gen). Un patrón clásico de pereza es devolver una subprograma anónima con estado guardado.
Desventajas: no hay soporte incorporado para yield, muchos módulos de CPAN carecen de compostibilidad. La recursión también está limitada por el tamaño de la pila.
¿Se puede implementar una lista infinita perezosa de números de Fibonacci en Perl sin desbordar la memoria?
Respuesta: Sí, mediante cierre:
sub fibonacci { my ($a, $b) = (0, 1); return sub { ($a, $b) = ($b, $a+$b); return $a; }; } my $fib = fibonacci(); print $fib->(), ", ", $fib->(), ", ", $fib->();
Pero si se almacenan los resultados en un arreglo, eventualmente desbordará la memoria (es decir, realmente el único "perezoso" es el generador mismo).
Historia
En un proyecto se escribió un iterador propio para recorrer un archivo enorme, implementado mediante un arreglo dentro de un objeto. El iterador cargó todo el archivo en memoria, y al crecer el archivo el servicio comenzó a generar OOM al trabajar con múltiples instancias.
Historia
Un cierre-generador para una secuencia de detalles para un informe provocó una fuga de memoria inesperada: dentro del cierre se mantenía accidentalmente una referencia a un gran arreglo de datos de entrada, lo que impedía que el recolector de basura funcionara.
Historia
Intentar implementar un generador complejo mediante recursión sin rastrear la profundidad llevó a superar el límite de la pila al procesar datos realmente grandes, en lugar de la esperada iteración "perezosa".