sub hanoi { my ($disks, $start, $end, $via) = @_; return () if $disks == 0; return ( hanoi($disks-1, $start, $via, $end), [$start, $end], hanoi($disks-1, $via, $end, $start) ); } #### sub iter_hanoi { my ($disks, $start, $end, $via) = @_; return sub{} if $disks == 0; # Base case is empty, replace with empty sub # List of iterators, wrapped in sub{}s to delay their evaluation: my @sub_iter = ( sub { iter_hanoi($disks-1, $start, $via, $end) }, # Explicit return is assigned to array for iterator to shift sub { my @middle_val = ([$start, $end]); sub {shift @middle_val} }, sub { iter_hanoi($disks-1, $via, $end, $start) }, ); # Below here is boilerplate: if you've done the above steps right, just plug # this in, and it works. It returns the first iterator from the list that # returns anything. # Grab and unwrap an iterator from the list my $iter = (shift @sub_iter)->(); return sub { my $rval; $iter = (shift @sub_iter)->() until ($rval = $iter->() or @sub_iter == 0); return $rval; } } #### sub iter_choose_n { my $n = pop; # Base cases get assigned to an array, which the iterator shifts through my @base_case = ([]); return sub{ shift @base_case } if $n == 0 or $n > @_; @base_case = (\@_); return sub { shift @base_case } if $n == @_; # otherwise.. my ($first, @rest) = @_; my @sub_iter = ( sub { my $recurse = iter_choose_n(@rest, $n-1); my $set; sub { ($set = $recurse->()) ? [$first, @$set] : () } }, sub { iter_choose_n(@rest, $n) } ); # Below here is boilerplate: if you've done the above steps right, just plug # this in, and it works. It returns the first iterator from the list that # returns anything. # Grab and unwrap an iterator from the list my $iter = (shift @sub_iter)->(); return sub { my $rval; $iter = (shift @sub_iter)->() until ($rval = $iter->() or @sub_iter == 0); return $rval; } }