Day 11 – Testing your Times Tables with Perl 6

It’s nearly the end of Winter term at Elf Primary School near the North Pole. A keen head for figures is very important to elves, and the little elves’ numeracy teacher, Ms Hopper, wants to make sure they keep up their arithmetical skills right up to the penultimate day of term. (The last day of term is reserved for watching films and playing shove-ha’penny).

The little elves have just learned their times tables (multiplication tables) up to 12, but they aren’t all as good at it as they’d like to be, and some of them will be helping out in the toy workshops just before Christmas, when they may need to quickly tell the big elves how many more toys of a particular type to make.

Fortunately Elf Hopper is a very smart elf with an excellent head for figures – and code – herself. So she whips up a quick console app to run on the little elves’ school-issue Perlix 6.0 boxen.

The program allows the little elves to test themselves on their 2 to 12 times tables by just running it, or if they supply a single numeric argument, they can try out any multiplication table they like.

#!/usr/bin/env perl6

use v6;

my $fixednum;
my %score;
my @exits = <exit quit>;

$fixednum = @*ARGS[0] || 0;
put "Type the answer, or quit or exit to end the test.";


loop {
    my $coefficient = (2..12).pick;
    my $number = $fixednum || (2..12).pick;

    my $answer = prompt ( "$coefficient × $number = " );
    my $rightanswer = $coefficient × $number;

    last if $answer.lc ~~ any @exits;

    if $answer == $rightanswer {
        put "Correct!";
        %score<correct>++;
    } else {
        put "Sorry, that wasn't right! The answer is $rightanswer";
    }
    %score<total>++;
}

if %score<total>:exists {
    my $pc = 100 * %score<correct> / %score<total>;
    put "You scored %score<correct> out of %score<total>, i.e. ", sprintf "%2.2f%%.", $pc;
}

Elf Hopper explains the code to the little elves as follows.

“Little elves! Here’s some background on how the program works.

I’ve added use v6; near the top in case so that the code can also run under Perl 5 and it will automatically engage the Perl 6 emulator.

You’ll see that the program picks up an optional parameter when run on the command line from the special @*ARGS array. This is the Perl6 equivalent of Perl 5’s @ARGV array.

In Perl 6, arrays, array elements and array slices always use the @ sigil, unlike Perl 5 where individual array elements use the $ sigil. In the same way, hashes and hash elements now always carry the % sigil, whether the whole hash, a slice of it or a single element is being used.

There’s also another symbol there, the asterisk ‘twigil’, *. That indicates that @*ARGS is a dynamic special variable.

The prompt and loop keywords are new in Perl 6 and both are admirably named!

  • prompt simply returns the value typed in by the user, in this case to a variable.
  • loop is one of Perl 6’s new block control keywords. A simple loop block like this one just creates an infinite loop which can be ended either by the programmer exiting explicity e.g. here with the last keyword when a condition is met; or for example by the user manually terminating the program.
  • Alternatively, loop can take three arguments and behave like a traditional C-style for loop. (In Perl 6, little elves, for is now only used for iterating over a list or other container.)

Inside the loop, little elves, you can see range objects. Everything is an object in Perl 6, so I can call the pick method on the range to return a random number. (Well, a non-cryptographically-secure pseudorandom number, anyway!)

The any keyword turns the @exits array into one of the many new useful data structures in Perl 6: a Junction. This makes finding an array element using the smartmatch operator ~~ straightforward. The last keyword exits the loop, as in Perl 5.

A Junction is a new type of container or list that allows many of the most useful comparisons such as any, all, one or none, which we do in Perl 5 with grep or a module such as List::Util, but it makes them a lot easier to type, and allows them to be performed concurrently! One side-effect of this is that Junctions are unordered: but they are mostly intended to result in a single true or false value, so that’s usually OK. Junctions are great for any time you quickly want to check a value against a short list of a few specific values, as here. But they’re also capable of letting you match against much larger sets of values if required.

At the top of the last code paragraph, you will see :exists applied to the %score<total> hash key. :exists is a Perl 6 adverb! Adverbs generally modify the way methods work. :exists is a subscript adverb. It is an adverb because it changes what happens when you read the hash key: instead of returning the value, you find out whether the value exists or not. This is usually a better alternative to using the defined method familiar to those of you who were paying attention in Perl 5 class.

The exists test is just there, of course, to ensure you don’t get an error if the user exits the program on the first go.

Why have I used chevrons to quote the hash key? Well, curly braces {} are the standard subscript operators for hash keys, as in Perl 5. However, most of the time you may want to use angle brackets / chevrons, as these provide automatic quotation of single-word keys. The simple {} braces used to do this in Perl 5, but no longer do in Perl 6. Strings inside the braces need to be quoted.

In Perl 6, the standard command for outputting text to a terminal is put. This outputs the following list items, followed by a newline. say and print are still available; say and put both print to standard output and append a newline; print does not append a newline.

If you use this program as well as knowing how it works, little elves, you will have the option, and knowledge, of whether, when and how to perform multiplication in your own head, and when it is best to let a Perl 6-powered computer do it. Your Christmas homework is to familiarise your elfselves with the Perl 6 documentation at https://docs.perl6.org.”

The little elves get to work with the multiplication test program, trying to outdo each other to get the highest perfect score. They find it so addictive that the contest even spills over to the final day of school, when they are supposed to be watching ‘Elf’!

🎅

One thought on “Day 11 – Testing your Times Tables with Perl 6

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.