Perl Weekly Challenge: Week 2

This weeks problems in the Perl Weekly Challenge were a little bit harder than last weeks but still well within my comfort zone I'm happy to report.

Challenge 1:

Write a script or one-liner to remove leading zeros from positive numbers.

My answer in Perl5 was:

perl -E 'say sprintf("%0d", shift)'

(Full code on Github.)

The same thing in Perl6 is:

perl6 -e 'sprintf("%0d", @*ARGS[0]).say'

(Full code on Github.)

Challenge 2:

Write a script that can convert integers to and from a base35 representation, using the characters 0-9 and A-Y. Dave Jacoby came up with nice description about base35, in case you needed some background.

This was a bit more involved. Here is the relevant parts of the code.

sub fromBase35 {
    my ($number) = @_;
    my $scale = (length $number) - 1;
    my %digits;
    @digits{(0 .. 9, 'A' .. 'Y')} = 0 .. 34;
    my $result;

    for my $digit (split '', $number) {
         my $base10 = $digits{uc $digit} // die "malformed base-35 number\n";
        $result += $base10 * 35 ** $scale;
        $scale--;
    }

    return $result;
}

sub toBase35 {
    my ($number) = @_;
    my @digits = (0 .. 9, 'A' .. 'Y');
    my @result;
    while ($number > 34) {
        my $digit = int($number / 35);
        push @result, $digits[$digit];
        $number -= ($digit * 35);
    }
    push @result, $digits[$number];

    return join '', @result;
}

(Full code on Github.)

Perl6 has base conversion built in to its String and Real classes so I didn't have to bother coding it myself.

#!/usr/bin/perl6
# Thanks to ugexe on #perl6 for help with option parsing.

multi sub MAIN (
    $number,            #= the number to convert
    Bool :$f! where .so #= convert base 35 number to base 10
) {
    say $number.parse-base(35);
}

multi sub MAIN (
    $number,
    Bool :$t! where .so #= convert base 10 number to base 35
) {
    say $number.base(35);
}

(Full code on Github.)

The only interesting thing here is the option handling. Like in the Perl5 version, I wanted to be able to specify -f and -t as options to the script. You will notice there are two subroutines called MAIN. Perl6, like C++, allows for multiple dispatch based on a functions signature. the -f and -t will automatically get converted to arguments to MAIN called $f and $t respectively so we can uses those to differentiate the signatures of the two MAINs.

where .so is a constraint that makes sure the argument, which would otherwise be a Str is converted to a Bool value.

the trailing ! marks this as a mandatory argument. As a positional parameter $number is mandatory by default though we could change that with a trailing ? (i.e. $number?) or by providing a default value (i.e $number = 0.)

I had a few problems getting this set up but ugexe on IRC (#perl6 on irc.freenode.net) helped me understand what to do.

Another nifty Perl6 feature for scripts is autogenerating a usage message like the one I had to write myself for the Perl5 version. A basic description for each option is also generated but you can customize it further by providing a Perl6 POD comment (the #= construct) with your own description.