Perl Weekly Challenge 163: the infinite loop
It is sad that, after more than two years of me doing Raku, I still don’t have any production code project to work on. Therefore, in order to keep my coding and Raku-ing (is that a term?) knowdledge, I try to solve every Perl Weekly Challenge tasks.In the following, the assigned tasks for Challenge 163.
and for the sake of some Perl 5, let’s do some stuff also in PostgreSQL Pl/Perl:
Last, the solutions in PostgreSQL PL/PgSQL:
PWC 163 - Task 1
This task was about doing an integer sum of bitwise ands within an array of numbers. It was not complicated, but it was requiring a full coverage of the index, that means a last step of using the very first and very last elements was required, as well as some conversions from and to integers:sub MAIN( *@n where { @n.grep( * ~~ Int ).elems == @n.elems } ) {
my $sum = 0;
$sum += ( @n[ $_ - 1 ].base( 2 ) +& @n[ $_ ].base( 2 ) ).Str.parse-base( 2 ) for 1 ..^ @n.elems;
$sum += ( @n[ 0 ].base( 2 ) +& @n[ * - 1 ].base( 2 ) ).Str.parse-base( 2 );
$sum.say;
}
PWC 163 - Task 2
This task was starting from an array of integers, that have to be progressively reduced by creating a new array with a sum of elements between the previous array and the previous element of the current array.sub MAIN( *@n where { @n.grep( * ~~ Int ).elems == @n.elems } ) {
my @matrix;
@matrix.push: [ @n ];
while ( @matrix[ * - 1 ].elems > 2 ) {
my @row;
@row.push: @matrix[ * - 1 ][ 1 ] ;
for 2 ..^ @matrix[ * - 1 ].elems {
@row.push: @matrix[ * - 1 ][ $_ ] + @row[ * - 1 ];
}
@matrix.push: [ @row ];
}
@matrix.push: [ @matrix[ * - 1 ][ * - 1 ] ];
say @matrix[ * - 1 ][ 0 ];
}
At every step, a new
@row
array of the @matrix
is built, and every element of the current @row
is made by the second element of the previous row in the matrix, then the sum of the same column element of the current row with the previous element of the current row.
Once the matrix has reached a single element row, the job is done.
PWC 163 - Task 1 in PostgreSQL PL/Perl
A quite simple translation of the Raku implementation:CREATE OR REPLACE FUNCTION
pwc163.task1_plperl( int[] )
RETURNS int
AS $CODE$
my ( $n ) = @_;
my $sum = 0;
for my $index ( 1 .. scalar( @$n ) - 1 ) {
my ( $a, $b ) = ( sprintf( '%03b', $n->[ $index - 1 ] ), sprintf( '%03b', $n->[ $index ] ) );
my $result = $a & $b;
elog( DEBUG, "Nums $n->[ $index - 1 ] and $n->[ $index ] => $a and $b => $result" );
$sum += oct( '0b'. $result );
}
my ( $a, $b ) = ( sprintf( '%03b', $n->[ 0 ] ), sprintf( '%03b', $n->[ -1 ] ) );
my $result = $a & $b;
$sum += oct( '0b'. $result );
return $sum;
$CODE$
LANGUAGE plperl;
Note that I use
sprintf
and oct
as ways to implement Raku base
and parse-base
methods. Despite this, the alghoritm is the same.
PWC 163 - Task 2 in PostgreSQL Pl/Perl
Same Raku implementation, but with a trick that made me run into an infinite loop:CREATE OR REPLACE FUNCTION
pwc163.task2_plperl( int[] )
RETURNS int
AS $CODE$
my ( $n ) = @_;
my @matrix;
push @matrix, [ @$n ];
while ( scalar( @{ $matrix[ -1 ] } ) > 2 ) {
my @row;
push @row, $matrix[ -1 ][ 1 ];
for my $index ( 2 .. scalar( @{ $matrix[ -1 ] } ) - 1 ) {
push @row, $matrix[ -1 ][ $index ] + $row[ -1 ];
}
elog( DEBUG, "Current row: " . join( ',', @row ) );
push @matrix, [ @row ];
}
return $matrix[ -1 ][ -1 ];
$CODE$
LANGUAGE plperl;
At first, I wrongly forgot that in Pl/Perl arrays are not really Perl arrays: they are an iterable object that smells like a Perl array, but needs to be derefenced pretty much any time. So when I looped up to
scalar $matrix[ -1 ]
I was issuing an infinite loop because I needed to deference the object asn an array!
PWC 163 - Task 1 in PostgreSQL Pl/PgSQL
Quite simple, since it is possible to cast a number tobit
and then to int
again:
CREATE OR REPLACE FUNCTION
pwc163.task1_plpgsql( n int[] )
RETURNS int
AS $CODE$
DECLARE
summy int := 0;
index int;
BEGIN
FOR index IN 2 .. array_length( n, 1 ) LOOP
summy := summy
+ ( n[ index - 1 ]::bit(8)
&
n[ index ]::bit( 8 ) )::int;
END LOOP;
summy := summy
+ ( n[ 1 ]::bit(8)
&
n[ array_length( n, 1 ) ]::bit( 8 ) )::int;
RETURN summy;
END
$CODE$
LANGUAGE plpgsql;
PWC 163 - Task 2 in PostgreSQL Pl/PgSQL
This time I took a slightly different approach than those in Raku and PL/Perl: I split the alghoritm in two steps. The first one was a function able to reduce an incoming array into the one with its sums, essentially producing from one row the next one. The second function was a simple loop over the previous one until the array got a single dimension.Take care that in SQL arrays start from
1
!
CREATE OR REPLACE FUNCTION
pwc163.task2_reduce( n int[] )
RETURNS int[]
AS $CODE$
DECLARE
summy int;
index int;
res int[];
BEGIN
FOR index IN 2 .. array_length( n, 1 ) LOOP
IF index = 2 THEN
res := array_append( res, n[ index ] );
ELSE
res := array_append( res, n[ index ] + res[ array_length( res, 1 ) ] );
END IF;
END LOOP;
RETURN res;
END
$CODE$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION
pwc163.task2_plpgsql( n int[] )
RETURNS int
AS $CODE$
DECLARE
BEGIN
WHILE array_length( n, 1 ) > 1 LOOP
n := pwc163.task2_reduce( n );
END LOOP;
RETURN n[ 1 ];
END
$CODE$
LANGUAGE plpgsql;