Perl 6 small stuff #16: All your base are belong to us

It’s the second week of the Perl Weekly Challenge, and like last week we’ve got two assignments — one “beginner” and one “advanced”.

The advanced assigment this time was: “Write a script that can convert integers to and from a base35 representation, using the characters 0–9 and A-Y.” Even though this is a blog mainly about Perl 6 I thought it’d be fun to start with my Perl 5 solutions to the advanced assigment, just so it’s even more easy to appreciate the simplicity of the Perl 6 solution… although not, as you will see, without some discussion.

PERL 5# Convert from base35 to base10
perl -E '%d = map { $_ => $c++ } (0..9,A..Y); $i = 1; for (reverse(split("", @ARGV[0]))) { $e += $i * $d{$_}; $i = $i * 35; } say $e' 1M5
# Output: 2000
# Convert from base10 to base35
perl -E '%d = map { $c++ => $_ } (0..9,A..Y); while ($ARGV[0] > 0) { push @n, $d{$ARGV[0] % 35}; $ARGV[0] = int($ARGV[0] / 35); } say join("", reverse(@n));' 2000
# Output: 1M5

So these are working one-liners but hardly readable ones. They also violate a lot of best practices. So I expanded them into a full script that’s easier to reuse and understand with added strict and error handling as well as support for positive/negative (+and - prefixes).

#!/usr/bin/env perl
#
# Usage:
# perl base35.pl [+-]NUMBER FROM-BASE, e.g.
#
# perl base35.pl 1000 10
# Output: SK
#
# perl base35.pl SK 35
# Output: 1000
#
# perl base35.pl -SK 35
# Output: -1000
use v5.18;say base35_conv(@ARGV);sub base35_conv {
my ($no, $base) = (uc(shift), shift);
if ($base != 10 && $base != 35) {
warn "Not a valid base, must be 10 or 35";
return -1;
}
if (($base == 35 && $no !~ /^[\+\-]{0,1}[0-9A-Y]+$/) || ($base == 10 && $no !~ /^[\+\-]{0,1}[0-9]+$/)) {
warn "You have to provide a valid number for the given base";
return -1;
}
my ($c, $e) = (0, 0);
my $prefix = $no =~ s/^(\+|-)// ? $1 : "";
my %d = map { if ($base == 35) { $_ => $c++ } else { $c++ => $_ } } (0..9,'A'..'Y');
if ($base == 35) {
my $i = 1;
for (reverse(split("", $no))) {
$e += $i * $d{$_};
$i = $i * 35;
}
}
else {
my @digits;
while ($no > 0) {
push @digits, $d{$no % 35};
$no = int($no / 35);
}
$e = join("", reverse(@digits));
}
return ( $prefix ? $prefix : "" ) . $e;
}

There’s really not much to comment about the code above. It works and is reasonably readable. It’s quite long, however, and that’s where Perl 6 comes in and destroys it.

PERL 6# Convert from base35 to base10
perl6 -e 'say "1M5".parse-base(35)'
# Output: 2000
# Convert from base10 to base35
perl6 -e 'say 2000.base(35)'
# Output: 1M5

At this you’re allowed to stop for a second an appreciate the simplicity of Perl 6. But:

Since these are built-in functions in Perl 6 this wasn’t — in my opinion — the best Perl 6 assigment. I guess the point of the assigment is to write a solution from scratch —had I solved the Perl 5 version of the assigment by using a ready-made CPAN module such as Math::Int2Base I’d feel that I cheated. Maybe that’s just me?


As for the “beginner” assigment this time — “Write a script or one-liner to remove leading zeros from positive numbers” — my Perl 6 and Perl 5 solutions are identical:

perl -E 'say "001000"*1;'
perl6 -e 'say "001000"*1;'
# Both output: 1000

Although the assignment wants a script that removes leading zeroes from positive numbers, this will just as easily remove them from negative numbers as well. These will also work on floating point numbers:

perl -E 'say "-001000"*1;'
perl6 -e 'say "-001000"*1;'
# Both output: -1000
perl -E 'say "001000.234"*1;'
perl6 -e 'say "001000.234"*1;'
# Both output: 1000.234

You can take it one step further with Perl 6, though. Should you for some reason — and I’m not able to think of a good one to be honest — want to do the same on a fraction, this is the way to do it:

perl6 -e 'say "003/4".Rat.nude.join("/");'
# Output: 3/4

.nude returns a two-element list with the numerator and denominator so that we can choose how to represent it (a naive say "3/4"*1; would print 0.75 and would therefore not be a satisfying solution considering how the assignment is specified).


So that’s it for now. It may sound a little silly to write this in a Perl 6 centric blog, but what made the assignment interesting this week was Perl 5.

I look forward to next week’s assignment already.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store