Like Perl 5, Perl 6 has a wealth of builtin operators for transforming values. In addition to the standard complement of arithmetic, logic, and bitwise operators that any programming language should have, Perl 6 also has a number of operator categories not commonly found in procedural or object-oriented languages, which can make solving certain problems extremely simple. Among these are *hyper operators*, a set of list-optimized transforms that automatically benefit from Perl 6's autothreading.

Binary hyper operators are specified by placing them between pairs of angle-quotes, without whitespace. For example, the multiplication hyper operator is `«*«`

or `»*»`

. But don't worry, you can also write those with doubled angle-bracket characters, which for most of us are a lot easier to type: `<<*<<`

and `>>*>>`

are the same as the angle-quote versions.

Let's write a program to try a few of these out.

#!/usr/bin/env perl6 # file: ex6.pl6 my @nums = ( 3, 4, 5, 6, 7 ); say @nums >>*>> 3; say 3 <<*<< @nums; # squares say @nums >>*>> @nums; say @nums <<*<< @nums; say @nums <<*>> @nums; # a better way to square say @nums >>**>> 2; # alternating operands say @nums >>+>> ( 2, 3 ); say ( 10, 20, 30 ) <<+<< @nums;

The direction of the arrows is important. For a given operator `X`

, the hyper operator expression `A >>X>> B`

will calculate `A[n] X B[n mod length of B]`

. In other words, each element of `A`

is combined with the corresponding element of `B`

via the operation `X`

until `B`

is exhausted, at which point it repeats from the beginning. We can see this in the "alternating operands" examples above, which provide the following output:

[5 7 7 9 9] (13 24 35 16 27)

In the first example, the numbers 2 and 3 are alternately added to the elements of the array `@nums`

. In the second line, the numbers 10, 20, and 30 are alternately added to the elements of `@nums`

. For this reason, unless both lists are of equal size, the arrows must point to the smaller list. If the pointy-side list is bigger, an error will be thrown.

The placement of operands is important for non-commutative operators. Here's an example.

#!/usr/bin/env perl # file: ex7.pl6 my @factors = ( 3, 11, 17 ); my @products = ( 9, 33, 51 ); say @factors >>/>> @products; say @factors <</<< @products; say @products >>/>> @factors; say @products <</<< @factors;

That program outputs:

[0.333333 0.333333 0.333333] [0.333333 0.333333 0.333333] [3 3 3] [3 3 3]

Because both lists are of equal size, we can point the arrow in either direction. But the division operator will divide the element on the left by the element on the right regardless of which list is pointed-at.

There are two special forms where the arrows point in opposite directions.

`>>X<<`

(facing form). The two lists are required to be of equal size. If they differ, it's an error.`<<X>>`

(opposing form). Either list can be smaller. In this case, whichever list is actually smaller at runtime will be deemed to be pointed-at.

In practice, I think most people will use the opposing form hyper operators the most often. But it's good to understand how the stricter versions operate.

This only scratches the surface of what hyper operators can do. Unary hyper operators are also possible, as are hyper operators that work on nested arrays, hashes, and user-defined hyper operators. Stay tuned for further posts.

Mike, you wrote:

#####

> (opposing form). Either list can be smaller. In this case, whichever list is actually smaller at runtime will be deemed to be pointed-at.

#####

But is this actually true for non-commutative operators such as '/'? Suppose I have:

#####

my @fewer_products = (9, 33);

my @factors = (3, 11, 17);

say @fewer_products > @factors;

# Output is: [3 3 0.529412]

say @factors > @fewer_products;

# Output is: [0.333333 0.333333 1.888889]

#####

In each case, the elements of the left-hand list are divided by the corresponding elements of the right-hand list until such time as the shorter of the two lists is exhausted, at which point we return to the first element of that list.

The "pointing" for '>' is going left-to-right in both cases, regardless of the length of each list at runtime.

Or am I missing something?