Day 7: Looping for fun and profit

Day 7: Looping for fun and profit

Any programmer who’s ever used a language which has them probably knows that loops are incredibly useful. In languages which provide them, foreach loops for iterating over arrays or lists tend to end up being very common. In Perl 5, these loops were provided by the foreach keyword, although you could also write for, sharing a keyword with the more general C-style for loops.

In Perl 6, that’s all changed.

for is now exclusively for iterating over lists. foreach has disappeared, and C-style for loops are handled by the new keyword loop. We’re not going to discuss those today, but we are going to focus on the new for loop, which combines with some other Perl 6 language features to deliver an enormously flexible and powerful construct.

Let’s look at a basic case.

for 1, 2, 3, 4 { .say }

There some immediately noticeable things about the syntax here. There are no brackets around the list construction, which is something that extends throughout Perl 6. Generally, you need a lot fewer brackety characters than in Perl 5. Much like in Perl 5, the loop variable is $_ by default. The method call of say with no invocant is the same as saying $_.say. Note that in Perl 6, you cannot say say with no argument to default to $_, you have to use the .say form, or specify $_ explicitly.

The block doesn’t have to be an ordinary block. It can be a pointy block, which lets you name your loop variable using the pointy block’s parameter capability.

for 1, 2, 3, 4 -> $i { $i.say }

A pointy block is a bit like an anonymous subroutine, except it doesn’t catch return exceptions. If you call return inside a pointy block, the enclosing routine will return.

Pointy blocks can take more than one parameter in their parameter lists. What happens if you do that?

for 1, 2, 3, 4 -> $i, $j { "$i, $j".say }

Well, if you run it, you get:

1 2
3 4

So what’s actually happened is that you’ve iterated over the list two elements at a time. This works for any number of parameters, with the minimum of one, degenerating to using $_ if you provide no explicit parameters yourself.

Having realised we can do this, what can we do with the generation of the list we iterate over? Well of course, we can use an array variable:

for @array { .say }

Although in many simple cases, we might prefer to use map: *.say;

Or a hyperoperator, if order and sequentiality isn’t important:


But neither of those things are today’s subject.

We might generate a list of numbers using the range constructor &infix:<..>:

for 1..4 { .say }

It’s very common that we want to generate a list of $n numbers beginning with 0, such as array indicies. We could write 0..$n-1, or using a variant of the range constructor 0..^$n, but Perl 6 provides a handy shortcut in the form of prefix:<^>:

for ^4 { .say }

Which will output:


One reason people often fall back on C-style for loops in Perl 5 is because they need to know what index in the array they are at for each item, or because they need to iterate over two or more arrays in parallel. Perl 6 offers a shortcut here, with the infix:<Z> zip operator.

for @array1 Z @array2 -> $one, $two { ... }

Assuming the two arrays are the same length, $one will be each element of @array1 and $two will be the corresponding element of @array2. If they are different lengths, iteration will stop when the end of the shorter array is reached.

With this knowledge, and the awareness that Perl 6 has lazy list generators, we can easily include the array index in the iteration:

for ^Inf Z @array -> $index, $item { ... }

Although if infinite lists make you nervous,

for ^@array.elems Z @array -> $index, $item { ... }

will give you the same results, but the most elegant presentation is probably:

for @array.kv -> $index, $item { ... }

@array.kv returns the keys and values interleaved, where the keys of an array are the element indices, so iterating over them two at a time has the desired effect.

Hopefully this post has given you an idea of the flexibility inherent in Perl 6’s for loops and how easy they can be to use for a variety of common tasks. Before we part, I’m going to answer one final question I know somebody’s been thinking.

What, you ask, if I want to iterate over four arrays at once?

for @one Z @two Z @three Z @four -> $one, $two, $three, $four { ... }

That’s a list associative infix operator, that is. Enjoy.

Day 6: Going Into Hyperspace

Day 6: Going Into Hyperspace

pmichaud introduced Perl 6’s hyper operators yesterday. I’d like to explore these powerful meta operators further.

First, for simplicity I’m going to code a helper function, lsay, to easily get nice-looking output of lists. The sub is created using our so you can use it on the REPL.

our sub lsay(@a) { @a.perl.say }

Then we can start looking at hyperoperator examples. For this post I’m going to use >> and << instead of » and «, mostly because they are easier on my eyes. (I’m afraid I may need to get glasses.) » and « are generally considered the true form of the operator, but the longer ASCII version will work as well.

First, the most basic: adding two lists of the same length:

> lsay (1, 2, 3, 4) <<+>> (3, 1, 3, 1)
[4, 3, 6, 5]
> lsay (1, 2, 3, 4) >>+<< (3, 1, 3, 1)
[4, 3, 6, 5]

If the lengths of the arrays are the same, there’s no difference between the two forms. But if the length is different:

> lsay (1, 2, 3, 4) <<+>> (3, 1)
[4, 3, 4, 5]
> lsay (1, 2, 3, 4) >>+<< (3, 1)
Sorry, right side is too short and not dwimmy.

The rule is that whatever is pointed to by the pointy end of the hyperoperator can be extended if it is shorter than the other end; it is extended by repeating the last element of that list. Whatever is at the blunt end of the hyperoperator cannot be extended. All combinations are allowed, so you can specify that only the left side can be extended (<<+<<), only the right side (>>+>>), both sides can be extended (<<+>>), or neither side can be extended (>>+<<). Single scalars extend as well:

> lsay (1, 2, 3, 4) >>+>> 2
[3, 4, 5, 6]
> lsay 3 <<+<< (1, 2, 3, 4)
[4, 5, 6, 7]

So that’s the basics of using hyperoperator with an infix operator. You can also use them with prefix and postfix operators:

> lsay ~<<(1, 2, 3, 4)
["1", "2", "3", "4"]
> my @a= (1, 2, 3, 4); @a>>++; lsay @a;
[2, 3, 4, 5]

You can also:

> lsay (0, pi/4, pi/2, pi, 2*pi)>>.sin
[0, 0.707106781186547, 1, 1.22464679914735e-16, -2.44929359829471e-16]
> lsay (-1, 0, 3, 42)>>.Str
["-1", "0", "3", "42"]

That is to say >>. works to call a method on every member of the list.

However much you are tempted to write @array>>.say, don’t do it. It may work in the current version of Rakudo, but by using the hyper operator you are promising the operation is parallelizable, and the order of the operations on the list(s) is not fixed. The hope is that future versions of Perl 6 will automatically run these operations in parallel.

Other quick notes: The hyperoperators don’t just work with the built-in set of operators. They will work with any new operator you define as well. (That works now in Rakudo, mostly.) They will work with the in-place operators, e.g. @a >>/=>> 2 to divide an entire array by 2. (This does not work in current Rakudo.) They will work with multi-dimensional lists, with trees, and with hashes; see S03 Hyper operators. (As far as I know, these do not yet work in Rakudo either.)

I don’t know too many examples yet of source code using hyperoperators extensively, though LastOfTheCarelessMen’s Vector class is a good if straightforward start — it implements an N-dimensional vector class without a single explicit loop.

Day 5: Metaoperators

Day 5: Metaoperators

In the Day 4 box, we saw an interesting implementation for the factorial function:

    sub fac(Int $n) {
        [*] 1..$n

Okay, so how does that work? Opening up today’s Advent box provides some answers!

Perl 6 has a number of different “meta operators” that modify the existing operators to perform more powerful functions.

The square brackets about are an example of the “reduce metaoperator”; they cause an infix operator to become a list operator that acts as though the infix was placed between each pair of elements. For example, the expression

    [+]  1, $a, 5, $b

is essentially the same as writing

    1 + $a + 5 + $b

This gives us a handy mechanism to “sum all elements in a list”:

    $sum = [+] @a;            # sum all elements of @a

Most of the infix operators (including user-defined operators) can be placed inside of square brackets to turn them into reductions:

    $prod = [*] @a;           # multiply all elements of @a

    $mean = ([+] @a) / @a;    # calculate mean of @a

    $sorted = [<=] @a;        # true if elements of @a are numerically sorted

    $min = [min] @a, @b;      # find the smallest element of @a and @b combined

So, in the factorial subroutine above, the expression [*] 1..$n returns the product of multiplying all of 1 through $n together.

Another useful metaoperator is the “hyper” operator. Placing »
and/or « (or the ASCII >> and << equivalents) next to an operator makes it “hyper”, which causes it operate on elements of lists. For example, the following calculates @c as the pairwise addition of the elements in @a and @b:

    @c = @a »+« @b;

In Perl 5, we’d generally write something like

    for ($i = 0; $i < @a; $i++) {
        $c[$i] = $a[$i] + $b[$i];

which is quite a bit longer.

As with the square brackets above, we can use hyper on a variety of operators, including user-defined operators:

    # increment all elements of @xyz

    # each element of @x is the smaller of @a and @b
    @x = @a »min« @b;

We can also flip the angles to enable a scalar to act like an array:

    # multiply each element of @a by 3.5
    @b = @a »*» 3.5;

    # multiply each element of @x by $m and add $b
    @y = @x »*» $m »+» $b;

    # invert all elements of @x
    @inv = 1 «/« @x;

    # concatenate @last, @first to produce @full
    @full = (@last »~» ', ') »~« @first;

Of course, reductions and hyper operators can be combined in expressions:

    # calculate the sum of squares of @x
    $sumsq = [+] ( @x »**» 2);

There are many other metaoperators available, including X (cross), R (reverse), S (sequential). In fact, the “in-place” operators such as +=, *=, ~=, are just meta forms created by suffixing an operator with an equals sign:

    $a += 5;      # same as $a = $a + 5;
    $b //= 7;     # same as $b = $b // 7;
    $c min= $d;   # same as $c = $c min $d;
Day 4: Testing

Day 4: Testing

Perl authors have a long tradition of shipping test cases with their modules, and in Perl 6 we plan to continue with that nice tradition.

And testing is very easy. The traditional perlish way is to print data in the Test Anything Protocol. But you don’t have to do that yourself, you can use a module for that.

Assume you have written a nice factorial function

 sub fac(Int $n) {
     [*] 1..$n

Currently it doesn’t matter for us how that function works – we want to find out if it does. So let’s test it:

 use v6;

 sub fac(Int $n) {
     [*] 1..$n

 use Test;
 plan 6;

 is fac(0), 1,  'fac(0) works';
 is fac(1), 1,  'fac(1) works';
 is fac(2), 2,  'fac(2) works';
 is fac(3), 6,  'fac(3) works';
 is fac(4), 24, 'fac(4) works';

 dies_ok { fac('oh noes i am a string') }, 'Can only call it with ints';

And let’s run it:

 $ perl6
 ok 1 - fac(0) works
 ok 2 - fac(1) works
 ok 3 - fac(2) works
 ok 4 - fac(3) works
 ok 5 - fac(4) works
 ok 6 - Can only call it with ints

In detail: use Test; loads the testing module, plan 6; declares that we plan to run six tests. Then five lines of the pattern is $got, $expected, $description follow. is() does string comparison, but since integers always stringify the same way, that’s fine.

Finally with dies_ok { $some_code }, $description we test that calling the function with a non-integer argument is a fatal error.

The output contains the test plan 1..6, followed by one line for each test. That starts with ok (or not ok if the test failed), the test number, space, dash, space and test description.

If you run more tests, you don’t want to look through every test output carefully, but you want a summary. The prove command from Perl 5 gives you such a summary:

 prove --exec perl6 .. ok
 All tests successful.
 Files=1, Tests=6, 11 wallclock secs ( 0.02 usr  0.00 sys + 10.26 cusr  0.17 csys = 10.45 CPU)
 Result: PASS

You can also put all your test files in a directory, let’s call it t/, and run prove recursively on all .t files in that dir:

 prove --exec perl6 -r t

Putting that line in your Makefile is also nice, so that you can just type
make test to run the tests.

Day 3: static types and multi subs

Day 3: static types and multi subs

The third box is ready for opening this Advent. Inside…well, looks like two gifts! Inside the box are static types and multi subs.

In Perl 5, $scalar variables could contain either references or values. Specifically, the values could be anything. They could be integers, strings, numbers, dates: you name it. This offers some flexibility, but at the cost of clarity.

Perl 6 is going to change that with its static types. If you want a particular variable, you place the type name in between my and $variable-type. As an example, to set up a variable to be an Int, one can do this:

my Int $days = 24;

Other static types are as follows:

  • my Str $phrase = "Hello World";
  • my Num $pi = 3.141e0;
  • my Rat $other_pi = 22/7;

If you still want the old behavior of the variables, you can either choose not to declare a static type or use Any instead.

This gift can easily go hand in hand with the second gift inside the box today: multi subs. What exactly are multi subs? In short, multi subs allow for the overloading of sub names. While multi subs can also do so much more, those are gifts for another day. For now, here are some subs that can be useful:

multi sub identify(Int $x) {
    return "$x is an integer.";

multi sub identify(Str $x) {
    return qq<"$x" is a string.>;

multi sub identify(Int $x, Str $y) {
    return "You have an integer $x, and a string \"$y\".";

multi sub identify(Str $x, Int $y) {
    return "You have a string \"$x\", and an integer $y.";

multi sub identify(Int $x, Int $y) {
    return "You have two integers $x and $y.";

multi sub identify(Str $x, Str $y) {
    return "You have two strings \"$x\" and \"$y\".";

say identify(42);
say identify("This rules!");
say identify(42, "This rules!");
say identify("This rules!", 42);
say identify("This rules!", "I agree!");
say identify(42, 24);

There is plenty to take advantage of with these two gifts. Try playing around with them, and keep coming back to our tree for more gifts that can use these features to their fullest extent. ☺

Day 2: The beauty of formatting

Day 2: The beauty of formatting

Unwrapping the second gift brought to you by Perl 6 this Advent, we find… a method named .fmt.

If you’re familiar with sprintf, you’ll feel right at home with .fmt. If you haven’t heard about sprintf before, or if you’ve heard of it but are a bit fuzzy on the details, you might want to skim the perldoc page. Don’t drown in it, though; it’s longish. Just savour it.

Back to .fmt, sprintf‘s spunky little sister. Here are a few ways to use .fmt to format strings and integers.

  say 42.fmt('%+d')                # '+42'
  say 42.fmt('%4d')                # '  42'
  say 42.fmt('%04d')               # '0042'
  say :16<1337f00d>.fmt('%X')      # '1337F00D'

All this is good and well, but not really more than a shorter method form of sprintf. Big deal, right?

What I haven’t told you yet is that .fmt is overloaded, and works differently on arrays (or more precisely, lists):

  say <huey dewey louie>.fmt       # 'huey dewey louie'
  say <10 11 12>.fmt('%x')         # 'a b c'
  say <1 2 3>.fmt('%02d', '; ')    # '01; 02; 03'

Similarly, it’s overridden on hashes (or rather, mappings):

  say { foo => 1, bar => 2 }.fmt   # 'foo     1
                                   #  bar     2'
  say { Apples => 5, Oranges => 10 }.fmt('%s cost %d euros')
                                   # 'Apples cost 5 euros
                                   #  Oranges cost 10 euros'
  say { huey => 1, dewey => 2, louie => 3 }.fmt('%s', ' -- ')
                                   # 'huey -- dewey -- louie'

The way hashing works may give your output a different order than the ones shown above. Oh, and there’s an overloaded .fmt for pairs as well, but it works analogously to the one for hashes.

.fmt is a useful little tool to have when you want to change some value, or an array or a hash of values, into to some given format. It’s like sprintf, but tailored to Do What You Mean for arrays and hashes, too.

There’s only one risk in all of this: Perl 6 might soil the reputation of the Perl family of languages by simply being too darn readable. In order to counter this risk, I leave a small parting gift in the form of a simple-but-dense Christmas tree printing Perl 6 one liner:

  $ perl6 -e 'say " "x 9-$_, "#"x$_*2-1 for flat 0..9,2 xx 3'

[*] If you are using Windows, remember you need to switch the quotes around
c:\>perl6.exe -e "say ' 'x 9-$_,'#'x$_*2-1 for flat 0..9,2 xx 3"