📘 Building the Pascal triangle using Perl 6

Generate the numbers of the Pascal triangle and print them.

The Pascal triangle is a sequence of rows of integers. It starts with a single 1 on the top row, and each following row has one number more, starting and ending with 1, while all of the other items are the sums of the two elements above it in the previous row. It is quite obvious from the illustration:

       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 25 6 1

To calculate the values of the next row, you may want to iterate over the values of the current row and make the sums with the numbers next to it. Let us use the functional style that Perl 6 offers.

Consider the fourth row, for example: 1 3 3 1. To make the fifth row, you can shift all the values by one position to the right and add them up to the current row:

  1 3 3 1
+   1 3 3 1
  1 4 6 4 1

In terms of arrays and assuming that the values of the fourth row are now contained in the @row variable, the calculations above are equivalent to the sum of the two arrays: current values in @row and a list of values that include 0 and all the values of @row. A trailing zero can be added to the current @row to make the arrays equally long.

This approach is illustrated by the following diagram:

  1 3 3 1 0
+ 0 1 3 3 1
  1 4 6 4 1

Now, write that down in the Perl 6 syntax using the technique from Task 53, Adding up two arrays.

@row = (|@row, 0) >>+<< (0, |@row);

Notice that the arrays are flattened with the help of a vertical bar: |@a. Without that, the (@row, 0) list is a list of two elements—an array and a scalar. Compare the output of the following test constructions:

my @row = 1, 2, 3;
say (@row, 0);  # ([1 2 3] 0)
say (|@row, 0); # (1 2 3 0)

Now, complete the program: we need to initialise the @row and add some printing instructions and create a loop:

my @row = 1;
say 1;
for 1..6 {
    @row = (|@row, 0) >>+<< (0, |@row);
    say @row.join(' ');
}

The program prints the first seven rows of the Pascal triangle. The rows are not centred and are aligned to the left side.

As an extra exercise, modify the program so that it prints the triangle as it is shown at the beginning of this task. For example, you can first generate rows and keep them in a separate array and then, knowing the length of the longest string, add some spaces in front of the rows before printing them.

📘 Building the product table using Perl 6

Generate and print the product table for the values from 1 to 10.

The task does not say anything about how to format the output.

First, let us print the results as a list with one line per one multiplication. In Perl 6, there is a cross operator X, which operates over lists and creates a cross product of them. Each element of the result list is a list of two elements coming from each of the operands of the X operator.

say "$_[0]×$_[1] = {[*] @$_}" for 1..10 X 1..10;

In each iteration, the loop variable $_ receives a list of two elements. They are printed inside the interpolated list: $_[0]×$_[1]. The string in double quotes also contains a block of code in curly braces, which is executed as a regular Perl 6 code. 

The reduction operation is used here to multiply the two elements. Of course, it is possible to do multiplication directly: $_[0]*$_[1].

The output looks like this:

1×1 = 1
1×2 = 2
1×3 = 3

. . .
10
×8 = 80
10×9 = 90
10×10 = 100

Now, let us print the result in the form of a table and try minimizing the code starting with two loops:

for 1..10 -> $x {
    for 1..10 -> $y {
        print $x * $y ~ "\t";
    }
    print "\n";
}

As the loop body of the inner cycle contains only one statement, it is possible to rewrite it by using the postfix forloop:

for 1..10 -> $x {
    print "{$x * $_}\t" for 1..10;
    print "\n";
}

Finally, join the output using the join function, which also helps to eliminate trailing tabulation characters at the end of lines:

for 1..10 -> $x {
    say join("\t", map {$x * $_}, 1..10);
}

It is also possible to call the functions as methods on lists:

for 1..10 -> $x {
   (1..10).map({$x * $_}).join("\t").say;
}

Further optimization isn’t easy because two variables are needed for multiplication, while only one $_ can be used as a default loop variable. Now the result is a proper table:

1  2 3 4  5  6  7  8  9  10
2  4 6 8  10 12 14 16 18 20
3  6 9 12 15 18 21 24 27 30
. . .

📘 Counting hash values in Perl 6

Having a hash, count the number of occurrences of each of its values.

For example, a hash is a collection mapping a car’s license plate to the colour of the car or a passport number to the name of the street where the person lives. In the first example, the task is to count how many cars of each colour there are. In the second example, we have to say how many people live on each street. But let’s simply count the colours of fruit 🙂

my %data =
    apple => 'red',     avocado => 'green',
    banana => 'yellow', grapefruit => 'orange',
    grapes => 'green',  kiwi => 'green',
    lemon => 'yellow',  orange => 'orange',
    pear => 'green',    plum => 'purple',
;

By the way, notice that Perl 6 is tolerant of the comma after the last value in the hash initializer list.

Now it is time to count the statistics that we need.

my %stat;
%stat{$_}++ for %data.values;
say %stat;

The valuesmethod returns a list of all the values that the hash contains. In the loop, they increment the values of the %stat hash. A new key is added to %stat as soon as a new value from %data is seen. An increment of the newly-created element sets the corresponding value to 1. Print the %stat hash and see the result. Notice that the output data is not ordered.

{green => 4, orange => 2, purple => 1, red => 1, yellow => 2}

📘 Sort hashes by parameter using Perl 6

Sort a list of hashes using data in their values.

This task is commonly performed to sort items where the sortable parameter is one of the values in the hash, for example, sorting a list of people by age.

my @people = (
    {
        name => 'Kevin', age => 20,
    },
    . . .
    {
        name => 'Amanda', age => 19,
    },
);

@people.sort({
    %^a<age> <=> %^b<age>
}).say;

The sort method uses an optional code block that customises the sorting procedure. It takes two arguments, compares them, and returns the result of the comparison.

In the example shown, %^a and %^b are the two placeholder variables created by the compiler. They alphabetically correspond to the first and the second arguments that the block receives.

Alternatively, it is possible to list the arguments in a pointy block explicitly:

@people.sort( -> %first, %second {
    %first<age> <=> %second<age>
}).say;

📘 How to transpose a matrix in Perl 6

Take a matrix and print its transposed version.

A matrix can be represented by nested arrays or lists. For example, here’s a square 2×2 matrix:

my @matrix = [1, 2],
             [3, 4];

This is how the transposed matrix should look:

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

Actually, the outer pair of square brackets, could be added to the initializer of the @matrix variable. Perl 6 simply converts the list ([1, 2], [3, 4])  to an array when assigning it to an array variable @matrix.

Transposing a matrix is extremely easy:

my @transposed = [Z] @matrix;

The [Z] operator is a reduction form of the zip operator. For the given small matrix, it’s action is equivalent to the following code:

my @transposed = [1, 2] Z [3, 4];

Despite the simplicity of the method, it works well with bigger matrices as well as non-square ones.

For the example @matrix in this task, the output of the program is the following:

[(1 3) (2 4)]

📘 Variadic parameters in a sub in Perl 6

Pass a few scalars to a sub and work with them as with an array inside the sub.

The task is to take a few scalar parameters and pass them to a single array in the subroutine. 

Here is an example of how to do that, prefixing an array name with a star:

sub h($sep, *@data) {
    @data.join($sep).say;
}

h(', ', 'red', 'green', 'blue');

In Perl 6, the *@data is called a slurpy parameter. It is an array that consumes all of the arguments passed to the function after the $sep argument. In the example above, three string values are passed. It is also possible to pass any other number of arguments:

h(', ', 'apple');

h(', ', 1, 2, 3, 4, 5);

Or even as a range of values, all of which land in the @data array.

h(', ', 'a' .. 'z');

It is important that in comparison to the solutions from Task 65, Passing arrays to subroutines, the $sep argument is mentioned first in the sub signature. If you put it at the end, the compiler refuses to accept that and complains:

Cannot put required parameter $sep after variadic parameters

📘 Passing arrays to subroutines in Perl 6

Pass data, contained in an array, to a subroutine.

In Perl 6, an array can be passed to a subroutine as easily as a scalar. You simply define it in a signature and pass it together with other arguments.

my @colours = <red green blue>;

sub f(@data, $sep) {
    @data.join($sep).say;
}

f(@colours, ', '); # Prints: red, green, blue

The @colours array is passed to the f sub, and it lands in the @data variable inside the sub. An additional second argument, $sep, receives its own data.

In cases when a sub expects separate scalars, and you’ve got your data in an array, flattening it helps:

sub g($a, $b, $c, $sep) {
    say "$a$sep$b$sep$c";
}
g(|@colours, ', '); # Prints: red, green, blue

In the sub call, an array name is prefixed with a vertical bar, and the compiler, therefore, knows that you are not passing an array as a whole but that you are using its elements as values to be assigned to the scalar arguments $a$b, and $c.

The number of elements in the array has to match with the number of corresponding subroutine arguments, otherwise one of the following errors occurs: Too few positionals passed or Too many positionals passed.