Home > Net >  explanation of perl script using lazy evaluation
explanation of perl script using lazy evaluation

Time:09-17

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..21 and when evaluated in scalar context it returns the length of the array. So $bytes = 21/8 = 2.625
  • my @indices = grep vec($bitmask, $_, 1), 0..$#_; Here $#_ is the last index in @_ which is 20. So this runs grep on the array 0..20. For each element in the array, it is checked if the corresponding bit value in $bitmask is set, if it is set it is saved in the @indices array.
  • $callback->( @_[@indices] ); : This calls the callback function with the array of indices which corresponds to the bits set in $bitmask. Since $bitmask is initially empty, in the first iteration, @indices will be equal to the empty array [].
  • vec($bitmask, $_, 8) and last for 0 .. $bytes; : Loops from 0..2 since $bytes == 2.625 it is rounded down to the nearest integer value. For each bytes index value in 0..2 the corresponding byte in $bitmask (treated now as an array of bytes) is incremented. The new byte value is returned from vec, if the returned value is nonzero the for loop exits (due to the and last part. 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 the for 0..$bytes for loop will execute.
  • redo if @indices != @_; runs the block (lines 7-12) again if the length of the @indices array is different from the length of @_ (i.e.: 21).
  • Related