# Perl Weekly Challenge 137: palindrome sums on long years

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 137.

And this week, as for the previous PWC, I had time to quickly implement the tasks also on PostgreSQL `plpgsql` language:

## PWC 137 - Task 1

The first task was about finding out if a given year is a long year, meaning an year with 53 weeks instead of the “ordinary” 52. This is a piece of cake using the `Date` builtin class and its `week-number` method:

``````sub MAIN() {
for 1900 .. 2100 -> \$year {
\$year.say if Date.new( '%04d-12-31'.sprintf( \$year ) ).week-number == 53;
}
}
``````

It could have also been written in a single line, using the postfix `for`, but the idea remains the same: iterate on every year, build a `Date` object for the last day of the year, and get the week number via the `week-number` method.

## PWC 137 - Task 2

In this task, given an integer value greater than `19` (that means, with at least two digits), we need to see if it is a Lychrel number. The idea is that, given a number, you keep adding it with its palindrome and see if the result is palindrome too. If it is, stop, the number is a Lychrel one, otherwise sum the result to its palindrome and go further.

``````sub MAIN( Int \$n where { 10 <= \$n <= 10000 }, Bool :\$verbose = False )  {

my ( \$result, \$iteration ) = \$n,0;
while ( \$result < 10_000_000 && \$iteration < 500 ) {
\$iteration++;
\$result += \$result.split( '' ).reverse.join;
if \$result == \$result.split( '' ).reverse.join {
'0'.say;
"Found \$result after \$iteration iterations".say if \$verbose;
exit;
}
}

'1'.say;
"Cannot find Lychrel number for \$n".say if \$verbose;
}
``````

The `\$result` contains the result of summing a number with its palindrome at every step. To get quickly the palindrome of a number I do use `split` to get its digits, `reverse` to reverse the array, and `join` to re-assemble it. It is not the only way, it can be used also `flip` on a `Str`, or other techniques.
The `\$verbose` flag allows for printing of some messages about the sattus of the computations.

## PWC 137 - Task 1 in PostgreSQL `plpgsql`

The implementation in `plpgsql` is a mirror of the implementation in Raku:

``````CREATE OR REPLACE FUNCTION
f_long_year()
RETURNS SETOF int
AS \$CODE\$
DECLARE
current_year int;
BEGIN
FOR current_year IN 1900 .. 2100 LOOP
IF date_part( 'week', make_Date( current_year, 12, 31 ) ) = 53 THEN
RETURN NEXT current_year;
END IF;
END LOOP;

RETURN;
END
\$CODE\$
LANGUAGE plpgsql;

``````

The trick here is to use `date_part`, that is a magical function that allows for extracting different information from a date. The date is built with `make_date`, that accepts the year, the month and the day. It is not mandatory, since a string concation is interpreted in the right sense in PostgreSQL, but using `make_date` makes the function easier to red.
It is also important to note that the `for` loop does a `RETURN NEXT`, that is kind of yeld: it allows the function to append a new value to the result set and proceed further with the looping. This allows the client to get results as a stream and the function to not store all of them while performing the computation.

## PWC 137 - Task 2 in PostgreSQL `plpgsql`

The second task is a `plpgsql` re-implementation of the Raku solution.

``````CREATE OR REPLACE FUNCTION
f_lychrel( n int, verb boolean default false )
RETURNS smallint
AS \$CODE\$
DECLARE
result    bigint := n;
iteration int    := 0;
BEGIN
IF n < 10 OR n > 10000 THEN
RAISE 'n is out of bounds!';
END IF;

WHILE result < 10000000 AND iteration < 500 LOOP
iteration = iteration + 1;
result    = result + reverse( result::text )::int;
IF result = reverse( result::text )::int THEN
IF verb THEN
RAISE INFO 'Found % after % iterations', result, iteration;
END IF;

RETURN 0;
END IF;

END LOOP;

RETURN 1;
END
\$CODE\$
LANGUAGE plpgsql;

``````

In the case of `plpgsql` we can exploit the `reverse` function that does the flipping of a given number, converted as a `text` (i.e., a string) and then reconvert the result as a number.
It is interesting to note how the `plpgsql` becomes quickly longer than the Raku implementation, and this is due to the syntax of conditionals but also to the fact that we need to check arguments within the core of the function, instead of being able to declare complex conditions on the argument list.

The article Perl Weekly Challenge 137: palindrome sums on long years has been posted by Luca Ferrari on November 1, 2021