package Iterator; use Exporter; @ISA = 'Exporter'; @EXPORT = qw(Iterator NEXTVAL imap igrep imap_l igrep_l list_iterator upto flatten append ); sub NEXTVAL { $_[0]->() } my %creator; sub Iterator (&) { return $_[0] unless $DEBUG; my $creator = (caller(1))[3]; if (exists $creator{$_[0]}) { warn "This iterator was already created by $creator{$_[0]}!!\n"; } $extant{$creator}++; bless $_[0] => 'Iter'; $creator{$_[0]} = $creator; print STDERR "+ $creator ($extant{$creator}) $_[0]\n"; return $_[0]; } sub Iter::DESTROY { my $iterator = shift; my $creator = delete $creator{$iterator}; $extant{$creator}--; print STDERR "- $creator ($extant{$creator}) $iterator\n"; } sub imap (&$) { my ($transform, $it) = @_; return Iterator { local $_ = NEXTVAL($it); undef $it, return unless defined $_; return $transform->(); } } sub imap_l (&$) { my ($transform, $it) = @_; return Iterator { my @a = NEXTVAL($it); return unless @a; return $transform->(@a); } } sub igrep (&$) { my ($is_interesting, $it) = @_; return Iterator { local $_; while (defined ($_ = NEXTVAL($it))) { return $_ if $is_interesting->(); } return; } } sub igrep_l (&$) { my ($is_interesting, $it) = @_; return Iterator { while (my @a = NEXTVAL($it)) { return @a if $is_interesting->(@a); } return; } } sub append { my @its = @_; return Iterator { my $val; until (@its == 0 || defined($val = NEXTVAL($its[0]))) { shift @its; } return if @its == 0; return $val; }; } sub flatten { my @stack = @_; return Iterator { print STDERR ">> In flatten: \n"; print STDERR ">> $creator{$_} $_\n" for @stack; while (@stack) { unless (UNIVERSAL::isa($stack[0], 'CODE')) { return shift @stack } my $val = NEXTVAL($stack[0]); if (@stack < 2 and UNIVERSAL::isa($val, 'CODE')) { unshift @stack, $val; } elsif (not defined $val) { shift @stack; } else { return $val } } return undef; } } sub list_iterator { my @items = @_; Iterator { return shift @items } } sub upto { my ($m, $n) = @_; return Iterator { return $m <= $n ? $m++ : undef; }; } 1;