{ package Iterator::Product; sub new { my $pkg = shift; @_ > 0 or die "$pkg->new() needs at least one iterator!"; @_ > 1 or return shift; if ( @_ > 2 ) # reduce! { my $car = shift; @_ = ( $car, $pkg->new( @_ ) ); } my $self = bless [@_], $pkg; $self->reset; $self } sub reset { my $self = shift; $self->[0]->reset; $self->_reset_inner; $self } sub _reset_inner { my $self = shift; $self->[1]->reset; $self->[2] = [ $self->[0]->value ]; $self } sub value { my $self = shift; $self->is_exhausted and die "past end"; $self->[1]->is_exhausted and $self->_reset_inner; ( @{ $self->[2] }, $self->[1]->value, ) } sub is_exhausted { my $self = shift; $self->[0]->is_exhausted && $self->[1]->is_exhausted } }