*From the given digits L, combine all possible numbers that are less than Y and that contain exactly X digits.*

Here are the initial data for the task:

my @L = (0, 1, 2, 5); my $X = 2; my $Y = 21;

And here is the full solution:

(grep * < $Y, grep 10 < * < 100, [X~] @L xx $X).join(', ').say;

In this one-liner, we first generate `$X`

copies of the digits in `@L`

as `@L xx $X`

, then cross-concatenate them using `[X~]`

, then filter the numbers that have two digits (`grep 10 < * < 100`

) and finally only leave the numbers less than `$Y`

using another filter (`grep * < $Y`

).

The program prints the following list:

$ raku ch-2.raku 10, 11, 12, 15, 20

If we know that `$Y`

is less than 100, we can simplify the conditions, for example:

(grep 10 <= * < $Y, [X~] @L xx $X).join(', ').say;

*Write a function that, from the given string, returns the last word that matches the given regex.*

The task is accomplished with the example of code, which I converted to use Raku regexes here:

last_word(' hello world', /<[ea]>l/); # 'hello' last_word("Don't match too much, Chet!", rx:i/ch.t/); # 'Chet!' last_word("spaces in regexp won't match", /'in re'/); # undef last_word((1..1e6).join(' '), /^(3.*?) ** 3/); # '399933'

To find the words in the string and reverse them so that you can find the first instead of the last, you can use a couple of method calls: `$str.words.reverse`

. But, actually, you even don’t need that as the `first`

method accepts the `:end`

parameter, which makes `first`

to find the *last* occurrence (I hope it is optimised internally not to scan all items).

sub last_word($str, $re) { say $str.words.first: * ~~ $re, :end; }

And that’s the whole body of the function in question. Run the program and confirm it prints the words that were expected in the task:

$ raku ch-1.raku hello Chet! Nil 399933

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*The task is to write a function that checks division by zero without explicitly comparing the denominator with zero.*

Let me offer a couple of solutions.

for -3 .. 3 -> $n { my $m = 42 / $n; print "42 / $n = "; say $m == Inf ?? 'Division by 0 detected' !! $m; }

The power of Raku is that you actually can divide by zero, but just make sure you use the result carefully. In this program, we check if the result is infinitive, and if so, print a message instead of a value:

$ raku ch-1.raku 42 / -3 = -14 42 / -2 = -21 42 / -1 = -42 42 / 0 = Division by 0 detected 42 / 1 = 42 42 / 2 = 21 42 / 3 = 14

An actual error will be thrown if we will try to use the result of division, for example, if we print it. In this case, you need to catch the error:

for -3 .. 3 -> $n { print "42 / $n = "; try { say 42 / $n; CATCH { default { say 'Division by 0 detected'; } } } }

This program produces the same output.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*List all Christmas days which fall on Sunday in 2019–2100.*

There was a similar task in the Euler project. Here is a possible solution for today’s problem.

(.say if .day-of-week == 7 given Date.new(year => $_, month => 12, day => 25) ) for 2019 .. 2100;

In the loop, this program generates the `Date`

objects for every possible Christmas for the selected years and then checks the value of the `day-of-week`

attribute of it. Notice how the `given`

keyword is utilised so that we can use a dot syntax to call different methods on the same object. See another example in one of the previous posts.

Run the program and it should print the following list:

2022-12-25 2033-12-25 2039-12-25 2044-12-25 2050-12-25 2061-12-25 2067-12-25 2072-12-25 2078-12-25 2089-12-25 2095-12-25

*Find all combinations of three numbers which give 12 in total and at least one of which is an even number.*

Here, first of all, you can limit yourself with checking the numbers below 12, but actually, there is a bigger simplification if you realise that if you have three numbers at hand, and their sum is 12, then it is not possible for them all to be odd. So we can simplify the task to:

*Find all combinations of three numbers which give 12 in total*.

A separate note is that there is no restriction for the numbers to be sequential. So, we can generate all possible combinations using the `combinations`

method: `for (1 .. 12).combinations(3)`

. The rest is simple: add them up with `[+]`

and print if the sum is 12.

.put if 12 == [+] $_ for (1 .. 12).combinations(3);

Note that if you swap the parts around the equals operator, then you will need parentheses, otherwise `[+]`

will be applied to the comparison `$_ == 12`

:

.put if([+] $_)== 12 for (1 .. 12).combinations(3);

Both programs print the same output:

$ raku ch-2.raku 1 2 9 1 3 8 1 4 7 1 5 6 2 3 7 2 4 6 3 4 5

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*Take the two words and count all letters in the second word, which are present in the first word.*

I have two solutions here, and I believe there is potential to make them shorter.

In the first solution, a set `$alphabet`

is created out of the letters from the first word `$pattern`

. Then you also split the second word into letters (`$test.comb`

) and filter that list so that only the letters from the `$alphabet`

can escape. And print the number of such cases (`.elems`

).

my ($pattern, $test) = @*ARGS; my $alphabet = set($pattern.comb); say $test.comb.grep({$alphabet{$_}:exists}).elems;

Run the program and pass two words to it:

$ raku ch-1.raku chancellor chocolate 8

In my second solution, no separate alphabet is needed; we scan the letters in the second word (`for $test.comb`

) and try to find them in the first word (`$pattern.match($_)`

). If it is found, then (`&&`

) the counter is incremented: `$count++`

.

my ($pattern, $test) = @*ARGS; my $count = 0; $pattern.match($_) && $count++ for $test.comb; say $count;

This program has the same interface as the previous one:

$ raku ch-1a.raku chancellor chocolate 8

And when you have the program completed, you understand that you can merge them to get a proper concise one-line solution!

my ($pattern, $test) = @*ARGS;say $test.comb.grep({$pattern.match($_)}).elems;

And that’s all for now.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

The so-called sexy prime pairs are pairs of prime numbers that differ by 6.

Generating prime numbers in Raku is an extremely simple task due to the built-in `is-prime`

method.

Let me demonstrate my straightforward solution, which can be reduced to a one-line probably. I applied a simple optimisation and excluded even numbers from consideration (knowing that 2 does not an cannot have a pair).

my $count = 0; for 1, 3 ... * -> $a { next unless $a.is-prime; my $b = $a + 6; next unless $b.is-prime; say "$a, $b"; last if ++$count == 10; }

The program checks if the current number `$a`

is prime, and if so, tests `$a + 6`

to be also a prime. If so, it prints them both, giving the following output:

5, 11 7, 13 11, 17 13, 19 17, 23 23, 29 31, 37 37, 43 41, 47 47, 53

→ GitHub repository

→ Navigation to the *Raku challenges* post series

It converges rather quickly, so even a few dozen of iterations is enough to get a good approximation.

The only thing to think about is not to calculate factorial inefficiently. So, I suggest to use the recursive factorial implementation which caches the already-calculated values. (Of course, you can write even more efficient program if you organise it with a couple of loops and variables.)

Having the factorial code ready, the whole program for computing *e* is a *half-liner*:

say [+] map 1 / *!, ^20;

The program prints 2.718281828459045.

Browse for the full program in the GitHub repository.

This post is my solution to the Task 1 of Week 21 of the Perl Weekly Challenge.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

Let us update the code so that it caches the already calculated values.

I am using multi-functions to distinguish between zero and non-zero arguments:

multi sub postfix:<!>(0) { 1 } multi sub postfix:<!>($n) { $n * ($n - 1)! }

Let us add a state variable to the second variant of the function so that it remembers the values and returns it immediately if it is already known:

multi sub postfix:<!>(0) { 1 } multi sub postfix:<!>($n) {state %factorial;%factorial{$n} //=$n * ($n - 1)! }

Notice how you can assign the new value if needed and return the result in a single line without any `if`

constructs. Also don’t forget the the last computed value is returned by the function.

As a homework, add some printing instructions to see how the function fills up the cache and test it on a few randomly ordered numbers:

say 5!; say 7!; say 4!;

Also take a look at the Memoize module.

]]>The queue implements three methods: `is_empty`

telling if the queue is empty, `insert_with_priority`

to add data attributed with a numeric priority value, and `pull_highest_priority_element`

to get the element which has higher priority, or if there are more than one, then the element which was added first.

Here is the implementation of the corresponding class:

class PriorityQueue { has %!queue; has $!count = 0; methodis_empty() { %!queue.elems == 0 } methodinsert_with_priority($data, $priority) { %!queue{$!count++} = { data => $data, priority => $priority, }; } methodpull_highest_priority_element() { my @sorted = %!queue.sort: {.value<priority>, -.key}; (%!queue{@sorted[*-1].key}:delete)<data>; } }

An instance of this class is using the `%!queue`

hash to store data and the counter `$!count`

, which increments with each inserted item.

has %!queue; has $!count = 0;

The key of the storage is the value of `$!count`

at the moment of insertion. Its values are the hashes containing the two pairs: `data`

and `priority`

:

%!queue{$!count++} = { data => $data, priority => $priority, };

Such two-layer architecture of the storage allows easy access when we need to remove the data item after it is pulled out from the queue.

To find the most prioritised item, we sort the storage by two parameters: priority and insertion number:

my @sorted = %!queue.sort: {.value<priority>, -.key};

Then, the last element is taken and immediately deleted from the storage. Raku’s `:delete`

adverb removes the element from the hash and returns it, so we do not need any temporary variables:

(%!queue{@sorted[*-1].key}:delete)<data>;

Note 1. Raku’s `sort`

routine accepts more than one sort element. This is exactly what we need to first sort by priority and then additionally sort by the order of insertion.

Note 2. To sort reversely, the simple solution is to negate the numeric value of the key: `-.key`

.

Note 3. Calling `pull_highest_priority_element`

on an empty queue generates an error. Thus, you must always check if it is empty or implement the check inside the pulling method.

Note 4. This code sorts the whole data storage, which is not optimal for big data sets. If you want a queue containing a lot of data, you should reorganise the `PriorityQueue`

class so that it keeps additional helper attributes to quickly find the needed data without scanning and sorting the whole storage.

The implementation of the `is_empty`

method is trivial:

%!queue.elems == 0

Finally, we can use the class. Let’s insert a few elements with different priorities and make a loop to pull the data in the correct order:

my $pq = PriorityQueue.new; $pq.insert_with_priority('A', 10); $pq.insert_with_priority('B', 20); $pq.insert_with_priority('C', 30); $pq.insert_with_priority('D', 20); say $pq.pull_highest_priority_element while !$pq.is_empty;

The program prints the data in the following order:

C

B

D

A

→ GitHub repository

→ Navigation to the *Raku challenges* post series

This is an interesting function that is defined kind of recursively but actually this is not a recursion, as the recurrent formula is using the function as an argument of itself.

Let me come to the solution in Raku, where you will immediately see the details of the definition. Multi-functions together with the `where`

clause are very handy here.

multi A($m, $n where $m == 0) { $n + 1 } multi A($m, $n where $m > 0 && $n == 0) { A($m - 1, 1) } multi A($m, $n where $m > 0 && $n > 0) { A($m - 1, A($m, $n - 1)) }

Notice that the condition in the last variant can be omitted but I prefer keeping it for clarity.

Let us test the function against small numbers and compare the results with the table on Wikipedia. Note that for arguments bigger than 4-5 the return value of the function are so high that it may take very long to compute it.

for ^4 X ^5 -> ($m, $n) { say "A($m, $n) = " ~ A($m, $n); }

This program prints the following lines:

A(0, 0) = 1 A(0, 1) = 2 A(0, 2) = 3 A(0, 3) = 4 A(0, 4) = 5 A(1, 0) = 2 A(1, 1) = 3 A(1, 2) = 4 A(1, 3) = 5 A(1, 4) = 6 A(2, 0) = 3 A(2, 1) = 5 A(2, 2) = 7 A(2, 3) = 9 A(2, 4) = 11 A(3, 0) = 5 A(3, 1) = 13 A(3, 2) = 29 A(3, 3) = 61 A(3, 4) = 125

Seems to be correct, so we can stop here.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*Print all Niven number up to 50, which are the numbers which are divisible the the sum of their digits.*

The solution is a one-liner:

.say if $_ %% [+] .comb for 1..50;

For the numbers in the range `1..50`

, split them into digits: `.comb`

, add up them: `[+]`

, and check if the number is divisible by it: `if $_ %%`

. If so, print the current value: `.say`

.

The program prints the following row (shown here in a single line for brevity, but the program prints each number on a separate line):

1 2 3 4 5 6 7 8 9 10 12 18 20 21 24 27 30 36 40 42 45 48 50

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*Generate a list of Regular numbers, which are the numbers, whose prime factors do not exceed 5.*

In my book *Using Raku*, there is an example of computing prime factors of a number. Actually, that solution can be simplified to the following code, as we don’t need to keep track of repeated factors:

my $max = 20; my @prime = grep *.is-prime, ^$max; for 1..$max -> $n { say "Prime factor(s) of $n: " ~ grep {$n %% $_}, @prime; }

For the numbers below 20, we have the following result:

$ raku prime-factors.raku Prime factor(s) of 1: Prime factor(s) of 2: 2 Prime factor(s) of 3: 3 Prime factor(s) of 4: 2 Prime factor(s) of 5: 5 Prime factor(s) of 6: 2 3 Prime factor(s) of 7: 7 Prime factor(s) of 8: 2 Prime factor(s) of 9: 3 Prime factor(s) of 10: 2 5 Prime factor(s) of 11: 11 Prime factor(s) of 12: 2 3 Prime factor(s) of 13: 13 Prime factor(s) of 14: 2 7 Prime factor(s) of 15: 3 5 Prime factor(s) of 16: 2 Prime factor(s) of 17: 17 Prime factor(s) of 18: 2 3 Prime factor(s) of 19: 19 Prime factor(s) of 20: 2 5

Now let’s use this program as a base for solving the task. If the number is Regular, then *all* of its prime factors are below and including 5, which you can express as:

all(map * <= 5, grep {$n %% $_}, @prime)

Finally, assemble the pieces together:

my $max = 60; my @prime = grep *.is-prime, ^$max; for 1..$max -> $n { say $n if all(map * <= 5, grep {$n %% $_}, @prime); }

You get these numbers in the output:

2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 40 45 48 50 54 60

Run the program with different maximum values and compare the result with the sequence listed at oeis.org/A051037.

*Print the Pascal triangle with the given number of rows.*

This task is directly solved in the same book, please find a solution on my site.

Let me add some code to print the triangle as a symmetrical shape:

my $rows = 10; my @row = 1; my @lines = gather { take 1; for 1 ..^ $rows { @row = (|@row, 0) >>+<< (0, |@row); take @row.join(' '); } }my $width = @lines[*-1].chars; .say for map({(' ' x ($width - $_.chars) / 2) ~ $_}, @lines);

This is the result for the requested 10 rows:

$ raku ch-2.raku 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1

Find the source files of today’s solutions at my GitHub repository.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*Remove leading zeros from positive numbers.*

So, we need to take a string such as `000042`

and print it as `42`

. Even here, there are two obvious solutions:

my $n = '00000042'; say +$n; say $n.Int;

A prefix form of `+`

converts the string to an integer. The same can be done by an explicit call of the `Int`

method.

The program prints the expected number:

$ raku ch-1.raku

42

42

*Convert a number to the one represented as a base-35 number and back.*

In Raku, there is a pair of routines, `base`

and `parse-base`

. They are ideal tools for solving the task.

To convert the number, use `base`

:

my $n = 2020; my $n35 = $n.base(35); say $n35;

This prints `1MP`

.

To convert it back to decimal system, use `parse-base`

:

my $n10 = $n35.parse-base(35); say $n10;

After this operation, the program prints the initial number `2020`

.

Look for the source files in the folder 002 of the GitHub repository.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

*Capitalise all small letters ‘e’ and count the number of replacements in the string ‘Perl Weekly Challenge.’*

Nothing fancy with the solution. Raku, as well as Perl, is good for such things.

my $s = 'Perl Weekly Challenge'; $s ~~ s:g/e/E/; say $/.elems; say $s;

The program prints:

$ raku ch-1.raku 5 PErl WEEkly ChallEngE

I think, one element needs a comment. The number of replacements is computed as `$/.elems`

, which is the number of the elements in the `$/`

variable, which, after the regex match, has the following content:

(｢e｣ ｢e｣ ｢e｣ ｢e｣ ｢e｣)

*Write a one-liner that, for the numbers from 1 to 20, prints ‘fizz’ if the number is divisible by 3 and ‘buzz’ if it is divisible by 5.*

This is a typical interview task which tests if you think of the numbers such as 15, which are divisible by both 3 and 5.

Let me offer an extremely straightforward solution:

say "$_ ", $_ %% 15 ?? 'fizzbuzz' !! $_ %% 3 ?? 'fizz' !! $_ %% 5 ?? 'buzz' !! '' for 1..20;

Output:

$ raku ch-2.raku 1 2 3 fizz 4 5 buzz 6 fizz 7 8 9 fizz 10 buzz 11 12 fizz 13 14 15 fizzbuzz 16 17 18 fizz 19 20 buzz

Find the source code in the directory 001 in my GitHub repository.

→ GitHub repository

→ Navigation to the *Raku challenges* post series

`X`

.
*Print all possible sorted combinations of $n numbers from the list 1 2 3 … $m.*

Note that it is not clear from the task that the valid combinations cannot contain the same numbers, so `1, 1`

or `3, 3`

are not valid. You can see it in the proposed output example.

First, let’s build the corresponding list and repeat it a few times:

[X] (1..$m) xx $n

The elements must be sorted, so `(3, 4)`

and `(4, 3)`

should both be converted to `(3, 4)`

. Apply the `sort`

method to all items:

([X] (1..$m) xx $n)\>>.sort

(Note the so-called unspace `\`

so that we can continue on the new line, as we need it because the solution will be a long change of method calls.)

To exclude the repeated elements, call `unique`

:

([X] (1..$m) xx $n)\ >>.sort.unique(:as(*.Str))

The `:as`

parameter tells what to do with the item before it can be compared using `===`

. This converts both copies of the sequence `(3, 4)`

to the same string `34`

.

As a home exercise, try using the `squish`

method instead of `unique`

and make the program work.

OK, now it’s time to exclude the elements with repeated numbers. This is my interpretation of the initial task, so you may have understood it differently.

([X] (1..$m) xx $n)\ >>.sort .unique(:as(*.Str)).grep(*.unique.elems == $n)

Here, I am filtering out everything where the number of unique elements differres from the required combination length `$n`

. (By the way, `$n`

must not be greater than `$m`

.)

Finally, order the sequence; we can use the same technique that was already used:

([X] (1..$m) xx $n)\ >>.sort .unique(:as(*.Str)) .grep(*.unique.elems == $n).sort(*.Str)

The main work is done. The last bits are to prepare the output in the requested format, and here is the whole program:

my $m = 5; my $n = 2; say'[ ',([X] (1..$m) xx $n)\ >>.sort .unique(:as(*.Str)) .grep(*.unique.elems == $n) .sort(*.Str).map({"[{.join(',')}]"}).join(', '),' ]';

For the given configuration, the program prints the following:

[ [1,2], [1,3], [1,4], [1,5], [2,3], [2,4], [2,5], [3,4], [3,5], [4,5] ]

Try different initial numbers, for example, 5 and 3:

[ [1,2,3], [1,2,4], [1,2,5], [1,3,4], [1,3,5], [1,4,5], [2,3,4], [2,3,5], [2,4,5], [3,4,5] ]

Or, which is also interesting to test, 5 and 5:

[ [1,2,3,4,5] ]

*Task: Print all possible letter combinations that the given digit string could produce on a phone keypad.*

(As a side note, I was surprised to see the image from an article on ResearchGate, meaning the author preferred a scientific website. But maybe it was just the picture with some letters on the 1 key )

This task is simpler than the previous one, just devote a few lines of code to prepare the initial data:

my @keypad = ' ', < _ , @>, < a b c >, < d e f >, < g h i >, < j k l >, < m n o >, < p q r s >, < t u v >, < w x y z >;

Notice that some of the elements have three, and some — four characters. For 0, I assumed the character to be a space. By the way, notice that in the `@keypad`

array, the first item is a string, while the rest are lists.

Having this, the rest is trivial:

my $n = 35; say [X~] @keypad[$n.comb];

When `$n`

is 35, the program prints the following combinations:

(dj dk dl ej ek el fj fk fl)

Let me ignore the format of the original answer this time.

Everything shown today can be also found on GitHub in my raku-challenges repository.

]]>*Print the Collatz Conjecture for the given integer number.*

You will see the definition of the Collatz sequence in the code. The conjecture is that for any starting number, the sequence ends with 1.

Here is the definition that is expressed directly in Raku code:

multi sub collatz($n where $n %% 2) { $n / 2 } multi sub collatz($n) { 3 * $n + 1 }

The two multi-functions choose between even and odd numbers.

As we know that the sequence *should* end with 1, let’s use the sequence operator with the expected final item.

my $start = 23; .say for $start, {collatz($_)} ... 1;

And indeed, that perfectly works:

$ raku ch-054-2.raku 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1

Try it with other numbers, for example, 42.

]]>Task:* find the first 20 so-called Gapful numbers,* which are the numbers that are divisible by the number formed by their first and the last digit. E.g., 132 passes the filter, as 132 / 12 divides without remainder.

The whole solution:

my $found = 0; for 100 ... * -> $n { my $m = [~] $n.comb[0, *-1]; next if $n % $m; last if $found++ == 20; say $n; }

Maybe the only thing to comment here is the line with `[~] $n.comb[0, *-1]`

. It does at least four things: converts the number into a string, splits it into characters, takes the first and the last elements of it and then concatenates the two characters.

*Task: Find and print all palindromic ddmmyyyy dates between 2000 and 3000.*

To loop over the date range, we can use a couple of `Date`

objects and the sequence operator:

for Date.new(year => 2000) ..^ Date.new(year => 3000) -> $date { . . . }

To find if a string is a palindrome, use the `flip`

method. The last bit to code is to print the date in the given format.

for Date.new(year => 2000) ..^ Date.new(year => 3000) -> $date { my $ddmmyyyy = sprintf '%02d%02d%d', .day, .month, .year given $date; say $ddmmyyyy if $ddmmyyyy eq $ddmmyyyy.flip; }

That’s it. The program prints 36 different dates, here are the first of them:

10022001 20022002 01022010 11022011 21022012 02022020 12022021 22022022 03022030 13022031 23022032 04022040 . . .

*Task: Find the first multiple of the given number, which only contains digits 0 and 1.*

This is a good task to use sequences. For the given number `$n`

, the sequence of its multiples can be generated as `$n, 2 * $n ... *`

. Lazy evaluation allows us not to worry about computing extra items.

Let’s simply find the first value that matches the condition expressed via a regex:

my $n = +@*ARGS[0]; say ($n, 2 * $n ... *).first: * ~~ /^<[01]>+$/;

Notice that it is important to convert the input string to an integer, thus you should not omit the prefix `+`

. Instead, explicit conversion can be done:

my $n = @*ARGS[0].Int;

For the input `55`

, this program prints `110`

as expected. Run it for different numbers:

$ raku ch-049-1.raku 55 110 $ raku ch-049-1.raku 14 10010 $ raku ch-049-1.raku 7 1001 $ raku ch-049-1.raku 143 1001 $ raku ch-049-1.raku 71 10011

Here’s a link to the GitHub repository, where you can find the source codes of today’s solutions.

]]>`123456789`

and insert the signs `+`

and `-`

between the digits so that the evaluated value of the new string equals 100. Actually, the problem is formulated a bit vague, as you may have less the 8 signs to get the result, for example: `1+`**23**-4+**56**+7+8+9 = 100

. The fun fact is that if you insert the signs between all the digits, you cannot find the solution.
The first step is obvious: split the string into characters:

my $string = '123456789'; my @nums = $string.comb; # 1 2 3 4 5 6 7 8 9

Then, you need an idea. My idea is to generate a sequence of numbers from 0 to 3⁸ and present them as numbers in base 3. Here, 3 is the number of operators we want: `+`

, `-`

, and no operation (or concatenation). 8 is the number of such positions (one less than the length of the string).

my $len = $string.chars - 1; my $span = 3 ** $len;

Now, prepare the sequences of operators:

for ^$span { my $mask = $_.base(3).fmt('%0' ~ $len ~ 'd'); my @signs = $mask.trans('0' => ' ', '1' => '+', '2' => '-').comb; . . . }

Inside the loop body, the `$mask`

variable and the `@signs`

array pass through the following combinations:

00000000 => 00000001 => + 00000002 => - 00000010 => + 00000011 => + + 00000012 => + - 00000020 => - 00000021 => - + 00000022 => - - 00000100 => + 00000101 => + + 00000102 => + - . . . 12111121 => + - + + + + - + 12111122 => + - + + + + - - 12111200 => + - + + + - 12111201 => + - + + + - + 12111202 => + - + + + - - 12111210 => + - + + + - + 12111211 => + - + + + - + + 12111212 => + - + + + - + - . . . 22222122 => - - - - - + - - 22222200 => - - - - - - 22222201 => - - - - - - + 22222202 => - - - - - - - 22222210 => - - - - - - + 22222211 => - - - - - - + + 22222212 => - - - - - - + - 22222220 => - - - - - - - 22222221 => - - - - - - - + 22222222 => - - - - - - - -

Having this done, the rest is straightforward. Zip the two arrays and remove the spaces. (The space in `@signs`

is required to keep the length of this array constant. If you replace 0 with an empty string: `'0' => ''`

, you get less positions and some digits will be skipped.)

my $expr = zip(@nums, @signs).flat.join('') ~ @nums[*-1]; $expr ~~ s:g/' '//;

Evaluate the expression and wait until it gives the desired result:

say $expr if EVAL($expr) == 100;

That’s it.

The program finds all the 11 possible solutions:

123+45-67+8-9 123+4-5+67-89 123-45-67+89 123-4-5-6-7+8-9 12+3+4+5-6-7+89 12+3-4+5+67+8+9 12-3-4+5-6+7+89 1+23-4+56+7+8+9 1+23-4+5+6+78-9 1+2+34-5+67-8+9 1+2+3-4+5+6+78+9

For the reference, here is the whole program, which you can also find on GitHub.

use MONKEY-SEE-NO-EVAL; my $string = '123456789'; my @nums = $string.comb; my $len = $string.chars - 1; my $span = 3 ** $len; for ^$span { my $mask = $_.base(3).fmt('%0' ~ $len ~ 'd'); my @signs = $mask.trans('0' => ' ', '1' => '+', '2' => '-').comb; my $expr = zip(@nums, @signs).flat.join('') ~ @nums[*-1]; $expr ~~ s:g/' '//; say $expr if EVAL($expr) == 100; }

P. S. In Raku, you must confirm that you are using `EVAL`

by adding the `use MONKEY-SEE-NO-EVAL;`

instruction. You may also notice that evaluating the expression so many times is relatively slow (1.5 minutes for the given input). To speed it up, you may try implementing the loop to go through the arrays and to perform the operations directly in the code.

Task: *You are given two or more arrays. Write a script to display values of each list at a given index.*

Here, I am using the same technique of looping over several arrays that I found out during the work on covid.observer:

my @a = < I L O V E Y O U >; my @b = < 2 4 0 3 2 0 1 9 >; my @c = < ! ? £ $ % ^ & * >; for @a Z @b Z @c -> ($a, $b, $c) { say "$a $b $c"; }

The program emits the following output:

$ raku ch-040-1.raku I 2 ! L 4 ? O 0 £ V 3 $ E 2 % Y 0 ^ O 1 & U 9 *

*Task: Print the first 20 Leonardo numbers.*

The definition of such sequences can be very easily expressed via multi-functions:

multi sub L(0) { 1 } multi sub L(1) { 1 } multi sub L($n) { L($n - 1) + L($n - 2) + 1 } say L($_) for ^20;

The program prints the first Leonardo numbers:

$ raku ch-041-2.raku 1 1 3 5 9 15 25 41 67 109 177 287 465 753 1219 1973 3193 5167 8361 13529

*Task: Print the numbers from 0 to 50 in octal format.*

There are a few ways of how to convert the number to the number with the given base in Raku, here is one of the simplest ones:

say "Decimal $_ = Octal {$_.base(8)}" for ^50;

The output stars with the following lines:

$ raku ch-042-1.raku Decimal 0 = Octal 0 Decimal 1 = Octal 1 Decimal 2 = Octal 2 Decimal 3 = Octal 3 Decimal 4 = Octal 4 Decimal 5 = Octal 5 Decimal 6 = Octal 6 Decimal 7 = Octal 7 Decimal 8 = Octal 10 Decimal 9 = Octal 11 Decimal 10 = Octal 12 . . .

You can find more solutions by browsing the Raku challenges category on my site. The solutions from today’s post are available on GitHub.

]]>The announcement was made during a keynote talk at the first day of this year’s Perl Conference (the so-called Conference in the Cloud, TPCiC). It was followed by the Perl Foundation news, an article on perl.com, and an e-book.

Isn’t that a great news? Well, yes and no. I have my personal feelings about this but I hope I can also see some other things that are not so much subjective.

The announcement was a surprise for many people, even for those who follow the Perl- and Raku-related news. On the other side, the announcement flow was very well coordinated, which means they prepared it behind the scene. Which is by itself is not how Open Source usually works.

Is it timely? Take another copy of the number 7, and come with me to the history of just 7 years deep (which is a huge timespan for a software product). In 2013, I hosted the European Perl Conference (YAPC::Europe at that time), and as the organiser, I proposed to have a discussion about the future Perl versions numbers. At that time, it was only 13 yeas since Perl 6 entered the scene, and it was also times when one could think it would never be released. Or it would, or not, . . . just don’t ask.

To support my idea, there was a conference newsletter, a panel discussion with the main Perl 6 people, and an offer to choose a personalised conference T-shirt where the attendees could choose whatever they like: Perl, Perl 5, Perl 6, Perl 7, or something else.

In response to the newsletter, I received a huge pile of negative comments. Well, I am using a neutral word now, as they were not simply negative, they were angry at least (use the words you know to continue the row).

*“I don’t think using the ‘Perl 7’ meme is a good idea.”*

*“‘Perl 7 t-shirts’ are a bad idea. They can only lead to misunderstandings and for those not ‘in the know’ it seems to express the failure of both Perl 5 and Perl 6.”*

*“I hate it when the complete Perl 6 community will be insulted like this, having discussions about Perl 7 like Perl 6 is a failure. Perl 6 is not a failure.”*

*“very disrespectful all this, I anyway will boycott YAPC::EU”*

These are just some examples that are still publicly visible. I don’t want you to read more of that stuff which landed in my inbox.

What do we hear today? I do not mean that the degree or the format of reactions changed a lot since then, I mean, what is the reaction to the recent Perl 7 announce.

There are a number of enthusiastic comments saying how great that is. There are a (seems to be smaller) number of reactions that something is broken with it.

Some people say that it was not a proper time 7 years ago to talk about Perl 7 as Raku was known under the name of Perl 6. I believe some of those who thinks like that were silently hoping Perl 6 would never be released and that Perl 5 should be the only true language in the Perl family. What is completely ignored here is the missed opportunity to have a massive media response after the rename.

What changed? Making the Perl-5-to-Perl-7 change is a very strong marketing step. Perl was number 9 in 2013, and it is number 16 in 2020. Let me use a silly marketing trick and say the chances to have a stronger output were 77% higher those days.

I completely agree that Perl 7 is a must thing. I completely disagree how it is being marketed now. There are two main problems. First, Perl and Raku are much further away from each other today, and the news are still biased towards the dominance of Perl over Raku. Here’s a keynote slide, where Perl 6 is simply stroked out.

Second, people who do not closely follow the progress with Perl 6/Raku think it really failed, and it never happened. ‘*Is there Perl 6 today? No! So, it failed, and they have Perl 7 now.*’ Kind of a PHP timeline resemblance in skipping the 6th version. Which, by the way, makes Perl a follower of a language which was often considered a killer of Perl.

I was so happy when Perl 5.10 was released, and I was so disappointed when the smartwatch operator was later announced an operator non grata, and that was an infamous change that indirectly demonstrated Perl will not be backwards-compatibile and it can break your program or a whole system at any moment.

Today, the brand new version was illustrated with an example of using the CGI module, which is considered extremely outdated for ages already. Looks like irony.

In any case, I believe a lot of developers are not digging that deep into the internal frictions of the Perl community, and, on the other side, the Perl Foundation seems to be willing to make the change smooth and would like to enforce some marketing efforts. Let’s see the outcome during the next 7 years

From a personal perspective, I received a strong confirmation I was so right seven years ago. I will also be happy to use Perl 7 as soon as it comes out, as its today’s version, Perl 5, is still one of the main languages that I use for living. It is great that it is evolving.

]]>Let me again solve a bit different task first, and just tell if such pair exists.

my $n = 9; say $n ∈ [X**] ((1..$n.sqrt) xx 2);

This program prints either True (e.g., for the input number 9) of False (e.g., for 45).

Here, the `1..$n.sqrt`

range is first repeated twice (`xx 2`

). Look at what it gives on an isolated example:

$ raku -e'dd (1..3) xx 2' (1..3, 1..3).Seq

Then, the `[X**]`

operator computes the power in all possible combinations:

$ raku -e'dd [X**] (1..3) xx 2' (1, 1, 1, 2, 4, 8, 3, 9, 27).Seq

Finally, we look if the given number exists in this sequence: `$n ∈ . . .`

.

Now, let us print the numbers of the possible solution as the original task requires. Use the same approach but in a bit brute-forced style using the loop over two arrays:

my $n = 9; # my $n = 45; for [X] (1..$n.sqrt) xx 2 -> ($x, $y) { say "$x^$y" and exit if $n == $x ** $y; } say 0;

If the solution is found, we print it and exit the program. Otherwise, print `0`

.

What is still missing, is the case when there are more than a single solution. For example, for 81:

my $n = 81; for [X] (1..$n.sqrt) xx 2 -> ($x, $y) { say "$x^$y" if $n == $x ** $y; }

How to elegantly print 0 if there is no solution? This is my homework for you. My quick solution would be the following:

say (gather { for [X] (1..$n.sqrt) xx 2 -> ($x, $y) { take "$x^$y" if $n == $x ** $y; } } || 0).join(', ');

For the input number 81, it prints `3^4, 9^2`

.

Look for the source code of the above examples on GitHub.

* * *

P. S. My posts in this series, Raku challenges, are aimed to train the ability of creating solutions directly from your head without spending more than half an hour for both the solution and its description. It may be incomplete, slightly incorrect or not optimal, but it allows to quickly pick the appropriate elements from the vast spectre of Raku features.

]]>