#! perl -slw use strict; sub loops { my @iters = map{ my @list = ( @$_, undef ); sub { $list[ @list ] = shift @list || () }; } @_; my @rv = map{ $iters[ $_ ]() } 0 .. $#iters; return sub { my $rv = [ @rv ]; for my $i ( reverse 0 .. $#iters ) { $rv[ $i ] = $iters[ $i ]() and return $rv; $rv[ $i ] = $iters[ $i ](); } return; }; } my $iter = loops [ 'a' .. 'd' ], [ 1 .. 4 ], [ 'me', 'you' ]; print "@$_" while $_ = $iter->(); __END__ [13:51:21.14] P:\test>loops a 1 me a 1 you a 2 me a 2 you a 3 me a 3 you b 1 me b 1 you b 2 me b 2 you b 3 me b 3 you c 1 me c 1 you c 2 me c 2 you c 3 me #### #! perl -w use strict; use List::Util qw( reduce ); use Data::Dumper; #package Sequence; #sub new { # my ($proto, $seq) = @_; # bless $seq, $proto; #} #sub seqsub(&) { # Sequences->new(@_); #} sub seq { my ($i, $elems) = (0, \@_); seqsub { $i < @$elems ? ( $elems->[ $i++ ] ) : do { $i = 0; () }; } } sub enumerate { local $Data::Dumper::Terse = 1; local $Data::Dumper::Indent = 0; my ($i, $seq) = (0, $_[0]); while (my @val = $seq->()) { @val = map { ref ($_) ? Dumper($_) : $_ } @val; printf "%2d => %s\n", $i++, "@val"; } $seq; } sub seq_prod2 { my ($s, $t) = @_; my @sval; seqsub { @sval = $s->() unless @sval; my @tval = $t->(); @tval ? ( @sval, @tval ) : do { @sval = $s->(); @sval ? ( @sval, $t->() ) : () }; } }; sub seq_prod { reduce { seq_prod2($a,$b) } @_ ; } sub seqs { map seq(@$_), @_; } sub seq_from_spec { seq_prod( seqs(@_) ); } sub seq_foreach { my ($seq, $fn) = @_; while (my @val = $seq->()) { $fn->(@val); } $seq; } sub seq_foreach_from_spec { my ($spec, $fn) = @_; seq_foreach( seq_from_spec( @$spec ), $fn ); } sub seq_filter { my ($seq, $filter_fn) = @_; seqsub { my @val; 1 while @val = $seq->() and !$filter_fn->(@val); return @val; } } sub seq_map { my ($seq, $fn) = @_; seqsub { my @val = $seq->(); @val ? $fn->(@val) : (); } } sub seq_reset { my $seq = shift; if ($seq) { 1 while $seq->(); } $seq; } sub seq_zip { my $seqs = seq( @_ ); # seq of seqs (!) my $seq_count = @_; seqsub { my @outvals; while (my $seq = $seqs->()) { if (my @val = $seq->()) { push @outvals, @val; } else { seq_reset( $seqs->() ) for 1 .. $seq_count; seq_reset( $seqs ); return (); } } return @outvals; } } my @site1 = qw( AATKKM aatkkm ); my @site2 = qw( GGGGGG gggggg ); my %counts; seq_foreach_from_spec( [ \(@site1, @site2) ], sub { seq_foreach( seq_zip( ( map seq(split//), @_ ) ), sub { $counts{"@_"}++ } ) } ); print Dumper(\%counts), "\n";