Archive for December, 2009

Day 5: Metaoperators

December 5, 2009

In the Day 4 box, we saw an interesting implementation for the factorial function:

    sub fac(Int $n) {
        [*] 1..$n
    }

Okay, so how does that work? Opening up today’s Advent box provides some answers!

Perl 6 has a number of different “meta operators” that modify the existing operators to perform more powerful functions.

The square brackets about are an example of the “reduce metaoperator”; they cause an infix operator to become a list operator that acts as though the infix was placed between each pair of elements. For example, the expression

    [+]  1, $a, 5, $b

is essentially the same as writing

    1 + $a + 5 + $b

This gives us a handy mechanism to “sum all elements in a list”:

    $sum = [+] @a;            # sum all elements of @a

Most of the infix operators (including user-defined operators) can be placed inside of square brackets to turn them into reductions:

    $prod = [*] @a;           # multiply all elements of @a

    $mean = ([+] @a) / @a;    # calculate mean of @a

    $sorted = [<=] @a;        # true if elements of @a are numerically sorted

    $min = [min] @a, @b;      # find the smallest element of @a and @b combined

So, in the factorial subroutine above, the expression [*] 1..$n returns the product of multiplying all of 1 through $n together.

Another useful metaoperator is the “hyper” operator. Placing »
and/or « (or the ASCII >> and << equivalents) next to an operator makes it “hyper”, which causes it operate on elements of lists. For example, the following calculates @c as the pairwise addition of the elements in @a and @b:

    @c = @a »+« @b;

In Perl 5, we’d generally write something like

    for ($i = 0; $i < @a; $i++) {
        $c[$i] = $a[$i] + $b[$i];
    }

which is quite a bit longer.

As with the square brackets above, we can use hyper on a variety of operators, including user-defined operators:

    # increment all elements of @xyz
    @xyz»++

    # each element of @x is the smaller of @a and @b
    @x = @a »min« @b;

We can also flip the angles to enable a scalar to act like an array:

    # multiply each element of @a by 3.5
    @b = @a »*» 3.5;

    # multiply each element of @x by $m and add $b
    @y = @x »*» $m »+» $b;

    # invert all elements of @x
    @inv = 1 «/« @x;

    # concatenate @last, @first to produce @full
    @full = (@last »~» ', ') »~« @first;

Of course, reductions and hyper operators can be combined in expressions:

    # calculate the sum of squares of @x
    $sumsq = [+] ( @x »**» 2);

There are many other metaoperators available, including X (cross), R (reverse), S (sequential). In fact, the “in-place” operators such as +=, *=, ~=, are just meta forms created by suffixing an operator with an equals sign:

    $a += 5;      # same as $a = $a + 5;
    $b //= 7;     # same as $b = $b // 7;
    $c min= $d;   # same as $c = $c min $d;

Day 4: Testing

December 4, 2009

Perl authors have a long tradition of shipping test cases with their modules, and in Perl 6 we plan to continue with that nice tradition.

And testing is very easy. The traditional perlish way is to print data in the Test Anything Protocol. But you don’t have to do that yourself, you can use a module for that.

Assume you have written a nice factorial function

 sub fac(Int $n) {
     [*] 1..$n
 }

Currently it doesn’t matter for us how that function works – we want to find out if it does. So let’s test it:

 use v6;

 sub fac(Int $n) {
     [*] 1..$n
 }

 use Test;
 plan 6;

 is fac(0), 1,  'fac(0) works';
 is fac(1), 1,  'fac(1) works';
 is fac(2), 2,  'fac(2) works';
 is fac(3), 6,  'fac(3) works';
 is fac(4), 24, 'fac(4) works';

 dies_ok { fac('oh noes i am a string') }, 'Can only call it with ints';

And let’s run it:

 $ perl6 fac-test.pl
 1..6
 ok 1 - fac(0) works
 ok 2 - fac(1) works
 ok 3 - fac(2) works
 ok 4 - fac(3) works
 ok 5 - fac(4) works
 ok 6 - Can only call it with ints

In detail: use Test; loads the testing module, plan 6; declares that we plan to run six tests. Then five lines of the pattern is $got, $expected, $description follow. is() does string comparison, but since integers always stringify the same way, that’s fine.

Finally with dies_ok { $some_code }, $description we test that calling the function with a non-integer argument is a fatal error.

The output contains the test plan 1..6, followed by one line for each test. That starts with ok (or not ok if the test failed), the test number, space, dash, space and test description.

If you run more tests, you don’t want to look through every test output carefully, but you want a summary. The prove command from Perl 5 gives you such a summary:

 prove --exec perl6 fac-test.pl
 fac-test.pl .. ok
 All tests successful.
 Files=1, Tests=6, 11 wallclock secs ( 0.02 usr  0.00 sys + 10.26 cusr  0.17 csys = 10.45 CPU)
 Result: PASS

You can also put all your test files in a directory, let’s call it t/, and run prove recursively on all .t files in that dir:

 prove --exec perl6 -r t

Putting that line in your Makefile is also nice, so that you can just type
make test to run the tests.

Day 3: static types and multi subs

December 3, 2009

The third box is ready for opening this Advent. Inside…well, looks like two gifts! Inside the box are static types and multi subs.

In Perl 5, $scalar variables could contain either references or values. Specifically, the values could be anything. They could be integers, strings, numbers, dates: you name it. This offers some flexibility, but at the cost of clarity.

Perl 6 is going to change that with its static types. If you want a particular variable, you place the type name in between my and $variable-type. As an example, to set up a variable to be an Int, one can do this:

my Int $days = 24;

Other static types are as follows:

  • my Str $phrase = "Hello World";
  • my Num $pi = 3.141e0;
  • my Rat $other_pi = 22/7;

If you still want the old behavior of the variables, you can either choose not to declare a static type or use Any instead.

This gift can easily go hand in hand with the second gift inside the box today: multi subs. What exactly are multi subs? In short, multi subs allow for the overloading of sub names. While multi subs can also do so much more, those are gifts for another day. For now, here are some subs that can be useful:


multi sub identify(Int $x) {
    return "$x is an integer.";
}

multi sub identify(Str $x) {
    return qq<"$x" is a string.>;
}

multi sub identify(Int $x, Str $y) {
    return "You have an integer $x, and a string \"$y\".";
}

multi sub identify(Str $x, Int $y) {
    return "You have a string \"$x\", and an integer $y.";
}

multi sub identify(Int $x, Int $y) {
    return "You have two integers $x and $y.";
}

multi sub identify(Str $x, Str $y) {
    return "You have two strings \"$x\" and \"$y\".";
}

say identify(42);
say identify("This rules!");
say identify(42, "This rules!");
say identify("This rules!", 42);
say identify("This rules!", "I agree!");
say identify(42, 24);

There is plenty to take advantage of with these two gifts. Try playing around with them, and keep coming back to our tree for more gifts that can use these features to their fullest extent. ☺

Day 2: The beauty of formatting

December 2, 2009

Unwrapping the second gift brought to you by Perl 6 this Advent, we find… a method named .fmt.

If you’re familiar with sprintf, you’ll feel right at home with .fmt. If you haven’t heard about sprintf before, or if you’ve heard of it but are a bit fuzzy on the details, you might want to skim the perldoc page. Don’t drown in it, though; it’s longish. Just savour it.

Back to .fmt, sprintf‘s spunky little sister. Here are a few ways to use .fmt to format strings and integers.

  say 42.fmt('%+d')                # '+42'
  say 42.fmt('%4d')                # '  42'
  say 42.fmt('%04d')               # '0042'
  say :16<1337f00d>.fmt('%X')      # '1337F00D'

All this is good and well, but not really more than a shorter method form of sprintf. Big deal, right?

What I haven’t told you yet is that .fmt is overloaded, and works differently on arrays (or more precisely, lists):

  say <huey dewey louie>.fmt       # 'huey dewey louie'
  say <10 11 12>.fmt('%x')         # 'a b c'
  say <1 2 3>.fmt('%02d', '; ')    # '01; 02; 03'

Similarly, it’s overridden on hashes (or rather, mappings):

  say { foo => 1, bar => 2 }.fmt   # 'foo     1
                                   #  bar     2'
  say { Apples => 5, Oranges => 10 }.fmt('%s cost %d euros')
                                   # 'Apples cost 5 euros
                                   #  Oranges cost 10 euros'
  say { huey => 1, dewey => 2, louie => 3 }.fmt('%s', ' -- ')
                                   # 'huey -- dewey -- louie'

The way hashing works may give your output a different order than the ones shown above. Oh, and there’s an overloaded .fmt for pairs as well, but it works analogously to the one for hashes.

.fmt is a useful little tool to have when you want to change some value, or an array or a hash of values, into to some given format. It’s like sprintf, but tailored to Do What You Mean for arrays and hashes, too.

There’s only one risk in all of this: Perl 6 might soil the reputation of the Perl family of languages by simply being too darn readable. In order to counter this risk, I leave a small parting gift in the form of a simple-but-dense Christmas tree printing Perl 6 one liner:

  $ perl6 -e 'say " "x 9-$_,"#"x$_*2-1 for 0..9,2 xx 3'

          #
         ###
        #####
       #######
      #########
     ###########
    #############
   ###############
  #################
         ###
         ###
         ###
[*] If you are using Windows, remember you need to switch the quotes around
c:\>perl6.exe -e "say ' 'x 9-$_,'#'x$_*2-1 for 0..9,2 xx 3"

Day 1: Getting Rakudo

December 1, 2009

There are many different partial implementations of Perl 6; at the moment, the most complete is Rakudo. There are a number of different ways to get it up and running, but if you have any interest in tracking or helping with the development, the best approach is to download directly from the source repositories and and build your own copy.

To do so, you will need Subversion (svn), git, Perl 5.8 or newer, a C compiler, and a make utility. On standard Linux-like systems (including OS X), you can build it like this:

$ git clone git://github.com/rakudo/rakudo.git
$ cd rakudo
$ perl Configure.pl --gen-parrot
$ make
$ make test
$ make install

Subversion is needed to run –gen-parrot — it actually uses svn to get the appropriate version of parrot and then compile it.  You will need to use the appropriate make command for your system.  (It’s generally nmake with MS Visual C++, I believe.)

For current Rakudo, make install doesn’t install into your path, it merely preps the system so that you can run the perl6 executable (created in the rakudo directory) from any other directory on your system. Once you have it going, you can easily play around with Perl 6 by executing perl6 with no arguments, putting you into a REPL environment where you can type commands and see what they do. This can be incredibly handy for trying to figure out how Perl 6 works. For instance,

$ ./perl6
> say "Hello world!";
Hello world!
> say (10/7).WHAT
Rat()
> say [+] (1..999).grep( { $_ % 3 == 0 || $_ % 5 == 0 } );
233168

The lines starting with $ and > are what you type; the other lines are Rakudo’s response. The first example is a simple say statement. The second creates a rational number and asks WHAT its type is (Rat). The third takes the list of numbers from 1 to 999, filters out the ones not divisible by 3 or 5, sums them, and then says the result. (This is Project Euler Problem #1, thanks to draegtun for reminding me of it.) We’ll try to explain how these things work in a future post.

One last thing. If you have any difficulties getting Rakudo working, the #perl6 channel on irc.freenode.net is usually very helpful.

Perl 6 Advent Calendar

December 1, 2009

In the grand tradition of previous Perl Advent Calendars, we are going to post something we like about Perl 6 every day in December until Christmas.  This post will be updated daily to link to each post as a sort of table of contents, or you can follow this blog in the normal way you follow blogs.

Day 1: Getting Rakudo
Day 2: The Beauty Of Formatting
Day 3: Static Types and Multi Subs
Day 4: Testing
Day 5: Metaoperators
Day 6: Going Into Hyperspace
Day 7: Looping For Fun and Profit
Day 8: .comb Your Constraints
Day 9: Having Beautiful Arguments And Parameters
Day 10: A Regex Story
Day 11: Classes, Attributes, Methods, and More
Day 12: Modules and Exporting
Day 13: Junctions
Day 14: Going to the Rats
Day 15: .pick Your Game
Day 16: We Call It “The Old Switcheroo”
Day 17: Making Snowmen
Day 18: Roles
Day 19: Whatever
Day 20: Little Big Things
Day 21: Grammars and Actions
Day 22: Operator Overloading
Day 23: Lazy Fruits From the Gather of Eden
Day 24: The Perl 6 Standard Grammar
Merry Christmas!


Follow

Get every new post delivered to your Inbox.

Join 44 other followers