I would like to understand what is happening in each step of the execution of the perl script below, I mean, I know what variables, hash, integer array are, but I don't know how they are interacting in this powerset construct using lazy evaluation.
I would also like to know which factors determine which step is the progress of the sub powerset(&@) subroutine.
For example, I would like to start printing from the sixth subset, not the first, so which values of which variables should I substitute?
use strict;
use warnings;
sub powerset(&@) {
my $callback = shift;
my $bitmask = '';
my $bytes = @_/8;
{
my @indices = grep vec($bitmask, $_, 1), 0..$#_;
$callback->( @_[@indices] );
vec($bitmask, $_, 8) and last for 0 .. $bytes;
redo if @indices != @_;
}
}
powerset { print "[@_]\n" } 1..21;
CodePudding user response:
my $bytes = @_/8;: Here@_is the array input argument so@_ = 1..21and when evaluated in scalar context it returns the length of the array. So$bytes = 21/8 = 2.625my @indices = grep vec($bitmask, $_, 1), 0..$#_;Here$#_is the last index in@_which is 20. So this runs grep on the array0..20. For each element in the array, it is checked if the corresponding bit value in$bitmaskis set, if it is set it is saved in the@indicesarray.$callback->( @_[@indices] );: This calls the callback function with the array of indices which corresponds to the bits set in$bitmask. Since$bitmaskis initially empty, in the first iteration,@indiceswill be equal to the empty array[].vec($bitmask, $_, 8) and last for 0 .. $bytes;: Loops from 0..2 since$bytes == 2.625it is rounded down to the nearest integer value. For each bytes index value in0..2the corresponding byte in$bitmask(treated now as an array of bytes) is incremented. The new byte value is returned fromvec, if the returned value is nonzero the for loop exits (due to theand lastpart. However, if the value of the byte was 255,vec($bitmask, $_, 8)will return a 0 (the byte value wraps around to zero) and the next iteration of thefor 0..$bytesforloop will execute.redo if @indices != @_;runs the block (lines 7-12) again if the length of the@indicesarray is different from the length of@_(i.e.: 21).
