Reading through the Generators page on the Python wiki inspired me to knock up something almost completely unlike generators using closures (something Perl has that Python hasn’t…) just for fun.
Edit: correction, thanks Bernhard.
Standard preamble…
use strict; use warnings;
The count() not-generator
sub count { my $cnt = -1; return sub { return ++$cnt; }; }
Helper function to make it easier to make not-generators
sub make_generator (&) { my $sub = $_[0]; my $finished = 0; return sub { return undef if $finished; local $_ = $sub->(); $finished = 1 unless defined $_; return $_; }; }
Composing not-generators
sub compose (&$) { my ($op, $generator) = @_; return sub { local $_ = $generator->(); return undef unless defined $_; return $op->($_); }; }
Takewhile …
sub takewhile (&$) { my ($match, $generator) = @_; return make_generator { local $_ = $generator->(); return $match->($_) ? $_ : undef; }; }
Foreach not-generator
I have to implement my own looping of course.
sub generator_for (&$) { my ($fn, $generator) = @_; while (defined(my $ret = $generator->())) { $fn->($ret); } }
Whew. And finally, after all that I can do the squares thing.
my $squares = compose { $_ * $_ } count(); my $bounded_squares = takewhile { $_ < 100 } $squares; generator_for { print @_, "\n" } $bounded_squares;