Wednesday, March 30, 2011

Perl 6 for finding non trivial powers less than 2 ^ 20

I recently noticed Terry Jones's blog post, "The eighty six non-trivial powers ≤ 2^20." I was immediately struck by how well this lent itself to being implemented in Perl 6, so I grabbed a handy Rakudo interpreter and translated it rather literally and then played with some slightly more idiomatic approaches. I still think I'm missing something with respect to the main loop, but I like what I came up with. The code is on github in my scripts repo.

In comparing the two (Terry's Python and my Perl), I really felt like this summed up the reason I want to code in Perl 6 more often. I work in Python for work, these days, and while it's a fine language with some very nice tools (django is especially nice), I frequently find myself wishing Rakudo were just a bit more production-ready.

So, without further ado, some thoughts about the two versions...

Code length is ignorable. Sure, the Perl is shorter in some areas and longer in others, but if that's interesting to you in terms of a mathematical problem, then there may be a problem.

However, in terms of clarity, I find two distinguishing features. One is strongly in Perl's favor, and one is mildly in Python's favor:

Pro Perl:

The largest thing I notice is that last block. It's much clearer to me that were'e concatenating the key with the value, after both are transformed in some way.

This reads a bit like, "print the formatted number in the key, followed by an equal followed by the values, joined internally with "^" and externally with commas."

Meanwhile the Python is something like, "print a formatted number, and equal and a formatted string where the number is in n and the formatted string is a comma joining a formatted pair of numbers joined with a "^" where the numbers are a and b where a and b are the tuples in powers indexed by n."

It's not that the code is *longer* that's the problem, but that it's far more disjoint. Even the indentation has to be complicated to suit the way they're mixing infix, functional and postfix grammatical elements.

Pro Python:

The declaration and use of powers is far cleaner in Python due to the handy defaultdict concept. This bypasses the defaulting that we do in Perl:

    (%powers{+$n} //= []).push([$a,$b]);

Beyond being punctuation-heavy, this is exactly the same underlying behavior as the Python. We default the bucket at $n to an empty list and then append the new item. The difference is that in Python the defaulting behavior is taken care of behind the scenes.

I say that this is minor because I understand this to be functionality that Rakudo Perl 6 has simply not implemented yet. You will eventually write:

    my Array %powers;
    ...
    %powers{$n}.push([$a, $b]);

very much like its Python counterpart.

Update: I'm told by the good folks on #perl6 that the right way to push onto a hash entry with a default empty array is:

    %powers.push: $n => [$a, $b];

Which is certainly cleaner than all of the  above, so woot!