My first experiment with Perl6

dpuu on 2008-12-23T19:40:34

So Patrick suggested on rakudo.org that playing with Microsoft's "Winter Scripting Games" would be a good way to get started with Rakudo.

I liked that idea, so I went to the first challenge (for beginners) -- simply count the number of pairs in a list. For their test data (7,5,7,7,13), the correct answer is to be "3", because "7" is paired 3 different ways.

I immediately thought of the new cross-product operator:

my @x = < 7 5 7 7 13 >;
say for @x X~X @x;

Here I found my first p6 gotcha. In perl5, "say for @x" will print the values of @x, one per line. In P6, $_ is not implicit in a function call to the builtins: you need to use a method call:

.say for @x X~X @x;

For something to be a pair, the two values will be the same. So what I need to do is to count the number of combinations of elements for which the value is the same:

say ((@x X==X @x).grep:{ $^same }).elems;

This works, but the result is way too big. The X==X operator counts every pairing twice; plus every element is paired with itself. We need to adjust the result:

say ((( @x X==X @x ).grep: { $^same }).elems - @x.elems)/2;

This indeed prints the correct answer. And it nicely shows the power of P6. But it also suggests that more power is needed. The need to adjust the result to eliminate duplicates is bad. What is really needed is an operator that crosses every element of a list with each element that is to its right in the original list -- what I might call a diagonal cross.

I need to figure out how to define such a meta-operator in P6 -- and then figure out how to implement it in Rakudo! If my diagonal-cross was defined, say, using "%==%" then the implementation of the original challenge would become:

say ((@x %==% @x).grep: { $^same }).elems

That would be truly awesome and, to my mind, elegant!


Reduction operator

david.romano on 2008-12-23T21:22:38

I went off of your examples and fiddled around a bit more with a reduction operator, and came up with this:

say (([+] @x XeqX @x) - @x.elems)/2;

It appears to work, and doesn't require the diagonal cross operator. The diagonal cross operator does seem like it would be a nice tool to have, tho' :-)

Re:Reduction operator

dpuu on 2008-12-23T23:25:33

Having thought it through, my "diagonal cross" should almost certainly be prefix, not infix -- I can't think what a diagonal cross with a different array would mean. So:

say [+] %eq% @x

if I can figure out how to implement it!