📘 Whatever (*) and WhateverCode in Perl 6

In Perl 6, the star character * can be associated with one of the predefined classes, Whatever and WhateverCode.

We’ll start with an object of the Whatever class.

say *.WHAT; # (Whatever)

The construction like 1 .. * creates a Range object, where its upper limit is not fixed to any particular number.

say (1 .. *).WHAT; # (Range)

Here is an example with a loop that prints the numbers from 5 to 10 line by line:

for (5 .. *) {
    .say;
    last if $_ == 10;
}

Now, try array indices and ask to take all the elements starting from the fourth one:

my @a = <2 4 6 8 10 12>;
say @a[3 .. *]; # (8 10 12)

The “three dots” operator in combination with a star creates a sequence.

say (1 ... *).WHAT; # (Seq)

You can use it when you need a lazy and potentially infinite list. A lazy list is a list whose elements are evaluated only when they are necessary for the execution of the programme.

In the following example, an array does not know its size, but you can read infinitely from it; the lazy list will supply new elements:

my @a = (100 ... *); 

for (0 .. 5) {
    say "Element $_ is @a[$_]";
}

This programme will print five lines corresponding to the first five elements of the @a array, which contain values from 100 to 105, including 105. If you change the range in the for loop from 0 .. 5 to 0 .. *, you will get a programme that prints infinitely.

It is possible to modify the algorithm for generating the new values of the sequence by giving a hint to the compiler:

my @a = (1, 2 ... *);    # step by 1
say @a[1..5];            # (2 3 4 5 6)

my @b = (2, 4 ... *);    # even numbers
say @b[1..5];            # (4 6 8 10 12)

my @c = (2, 4, 8 ... *); # powers of two
say @c[1..5];            # (4 8 16 32 64)

Together with a list repetition operator, xx, the Whatever object forms an infinite list containing the same value.

my @default_values = 'NULL' xx *;

Now, let’s move on to the WhateverCode object. It is an anonymous code block, which is a good match for simple functions, such as these:

my $f = * ** 2;  # square
say $f(16);      # 256 

my $xy = * ** *; # power of any
say $xy(3, 4);   # 81

In Perl 6, the transformation from a code with a star to an anonymous code block is called whatever-currying. In the traditional style of programming, you introduce a variable to get the same result. In Perl 6, a compiler creates that for you. The following two examples are equivalent to the two above.

# An anonymous code block with one argument $x
my $f = -> $x {$x ** 2};
say $f(16); # 256

# A block with two arguments; names are alphabetically sorted
my $xy = {$^a ** $^b};
say $xy(3, 4); # 81

Whatever-currying is also happening, for example, when we want to refer to the last elements of an array using negative indices. In the following example, we pick array elements from the fourth to the second-to-last one.

my @a = <2 4 6 8 10 12>;
say @a[3 .. *-2]; # (8 10)

In Perl 5, you could get the last element of an array with the -1 index. In Perl 6, the access @a[-1] will generate an error:

 Unsupported use of a negative -1 subscript to index from the end; in Perl 6 please use a function such as *-1 

So, you need to add a star:

say @a[*-1]; # 12

Here, the compiler will convert @a[*-1] into the following code:

@a[@a.elems - 1]

Another common use case of WhateverCode is to provide a compiler with a rule for generating infinite sequences.

my @f = 0, 1, * + * ... *;
say @f[1..7].join(', '); # 1, 1, 2, 3, 5, 8, 13

This example creates a lazy list containing the Fibonacci numbers. The * + * construction will be implicitly replaced with something like {$^a + $^b}. Note that the first two stars in the example are part of what will become an anonymous code block, while the last one is a single Whatever object.

📘 Programming for the Internet in Perl 6

The simplest way to build a web server in Perl 6 is to use a PSGI server called Bailador. This is a module that you can find on the official page with the list of Perl 6 modules: modules.perl6.org. If you are using the Rakudo Star distribution, use the panda* command line utility to install the module.

$ panda install Bailador

Bailador copies the interface of the well-known framework Dancer for Perl 5. The name is the same but in Spanish.

Here is the minimal programme that implements the web server.

use Bailador; 

get '/' => sub {
    'Hello, world!'
} 

baile;

The programme describes the action, which the server does in response to the request to its home page. The baile (dance in Spanish) method starts the main loop of the PSGI server.

Run the programme:

$ perl6 web1.pl

You will get the output informing you that the server is ready to accept requests.

Entering the development dance floor: http://0.0.0.0:3000
[2016-12-27T20:27:34Z] Started HTTP server.

Open that page in a browser, and you will see the desired output: “Hello, world!”

The next step is to parse the URL and respond accordingly. Bailador allows extract parameters from the URL with the colon syntax:

get '/:name' => sub ($name) {
    "Hello, $name!"
}

Please note that you cannot omit the space after the sub keyword. There is an alternative. As the sub is anonymous, you may use the pointy block instead:

get '/:name' => -> $name {
    "Hello, $name!"
}

Add it to the programme, restart the server, and go to, for example, http://0.0.0.0:3000/abc. You should get the “Hello, abc” output in the browser.

Bailador is happy to accept regexes instead of the fixed URLs. For example, let’s create the URL /square-of/N, where the N can be any non-negative integer.

get / 'square-of/' (<digit>+) / => sub ($n) {
    $n * $n
}

The regex pattern / ‘square-of/’ (<digit>+) / contains the capturing part, and so the variable $n will be set to the number from the URL. As Bailador reads the address patterns in the order they appear in the file, make sure to put the method above the handler of /name. Now, test how it works at http://0.0.0.0:3000/square-of/5; it should print 25.

It is possible to access some environment variables in the URL handler. Use the request method and take the request.env hash from it, as is demonstrated in the example:

get '/ua' => sub {
    request.env<HTTP_USER_AGENT> ~
    '<br />' ~
    request.env<QUERY_STRING>
}

The page http://0.0.0.0:3000/ua?key=value will now print the user agent name and list the query parameters of the request.

After we generate the output from the Perl code, let us move to using templates. Bailador will search for the template files in the views directory.

Save a simple text template to views/test.tt, and use it in the server like this:

use Bailador; 

get '/form' => sub {
    template 'test.tt';
} 

baile;

To print something inside the template, pass the data in hash:

get '/form/:name' => sub ($name) {
    template 'name.tt', {name => $name}
}

You can access the data from a template. It receives the argument containing everything that you just passed.

% my ($params) = @_; 
Hi, <%= $params<name> %>!

At the moment of writing this book, panda was about to become outdated, and the new recommended tool will be zef. Please refer to the documentation of your Perl 6 distribution on how to install modules.

📘 Unicode in Perl 6

The strings in Perl 6 are internally handled in the format called NFG (Normalization Form Grapheme). From a practical point of view, that means that, for any symbol, you can get its NFC, NFD, NFKC and KFKD forms. I will refer you to read about the details of these formats to the Unicode standard. In simple words, these are different canonical and decomposed forms of a symbol.

There are four methods with those names, and you may call them on character strings:

say $s.NFC; # codepoint
say $s.NFD;
say $s.NFKC;
say $s.NFKD;

The full canonical name of a character is returned by the method uniname:

say 'λ'.uniname; # GREEK SMALL LETTER LAMDA

In the string class, the encode method is defined; it helps to see how the string is built internally in one of the Unicode charsets:

my $name = 'naïve';
say $name.encode('UTF-8');  # utf8:0x<6e 61 c3 af 76 65>
say $name.encode('UTF-16'); # utf16:0x<6e 61 ef 76 65>

As an exercise, examine the output for the following characters. The unidump function, shown below, prints some characteristics of the Unicode characters.

unidump('☭');
unidump('ы');
unidump('å');
unidump('é');
unidump('ϔ');
# One of the few characters, for which all the four
# canonical forms are different.

unidump('й');
unidump('²');
unidump('Æ'); 

sub unidump($s) {
    say $s;
    say $s.chars; # number of graphemes
    say $s.NFC;   # code point
    say $s.NFD;
    say $s.NFKC;
    say $s.NFKD;
    say $s.uniname; # the Unicode name of the character
    say $s.uniprop; # the Unicode properties of the first grapheme
    say $s.NFD.list; # as a list
    say $s.encode('UTF-8').elems; # number of bytes
    say $s.encode('UTF-16').elems;
    say $s.encode('UTF-8'); # as utf8:0x<...>
    say '';
}

The NFKC and NFKD forms, in particular, transform the sub- and superscript to regular digits.

say '2'.NFKD; # NFKD:0x<0032>
say '²'.NFKD; # NFKD:0x<0032>

The unimatch function indicates whether a character belongs to one of the Unicode character groups.

say unimatch('道', 'CJK'); # True

Be warned, because some characters can look the same but are in fact different characters in different parts of the Unicode table.

say unimatch('ї', 'Cyrillic'); # True
say unimatch('ï', 'Cyrillic'); # False

The characters in the example are CYRILLIC SMALL LETTER YI and LATIN SMALL LETTER I WITH DIAERESIS, respectively; their NFD representations are 0x<0456 0308> and 0x<0069 0308>.

It is also possible to check the Unicode properties using regexes:

say 1 if 'э' ~~ /<:Cyrillic>/;
say 1 if 'э' ~~ /<:Ll>/; # Letter lowercase

Use the uniprop method to get the properties:

say "x".uniprop; # Ll

To create a Unicode string directly, you may use the constructor of the Uni class:

say Uni.new(0x0439).Str;     # й
say Uni.new(0xcf, 0x94).Str; # Ï

Also, you can embed copepoints in the string:

say "\x0439";   # й
say "\xcf\x94"; # Ï

📘 Working with files and directories in Perl 6

To get the content of a file, use the slurp built-in function, which reads the whole file and returns a string.

say slurp "file.txt";

The function that does the opposite is called spurt, it writes the string to a file.

Let us implement the Unix’s cp command in Perl 6.

my ($source, $dest) = @*ARGS; 

my $data = slurp $source;
spurt $dest, $data;

By default, either a new destination file will be created or rewritten if it already exists. You can open the file in the append mode by adding the :append value in the third argument:

spurt $dest, $data, :append;

Another mode, :createonly, generates an error if the file exists.

spurt $dest, $data, :createonly;

Both slurp and spurt accept an argument with the encoding name:

my ($source, $dest) = @*ARGS; 

my $data = slurp $source, enc => 'UTF-8';
spurt $dest, $data, enc => 'UTF-16';

The Str class inherits (from the Cool class) the IO method that returns an object of the IO::Path class. It contains some useful information about the file.

For example, this is how you can get the absolute path to a local file:

say 'file.txt'.IO.abspath;

The IO.dir method prints the content of a directory:

say '.'.IO.dir;

The IO.extension method returns an extension of a file:

say $filename.IO.extension;
say $filename.IO.extension;

Finally, there are one-letter named methods for making checks of the file’s or directory’s existence or checking its properties:

say 1 if 'file.txt'.IO.e; # same as -e 'file.txt' in Perl 5 (file exists)
say 1 if 'file.txt'.IO.f; # -f (is a file)
say 1 if '..'.IO.d;       # -d (is a directory)

📘 Database access in Perl 6

Install the DBIish module to get a powerful tool for working with databases*:

$ panda install DBIish

You also will need the database driver; for example, libmysqlclient for working with MySQL. Check the documentation of the DBIish module on modules.perl6.org if you want to work with a different database engine.

The module provides an interface similar to the DBI’s in Perl 5. You obtain a database handler, $dbh, and they work via the statement handler, $sth. Let us see some details in the following example.

use DBIish; 
# Connecting to a remote database
my $dbh = DBIish.connect(
    'mysql',
    :host<example.com>,
    :port(3306),
    :database<test>,
    :user<test>,
    :password<test_password>
); 

# Now, prepare the statement to get all the data from a table
my $sth = $dbh.prepare("select * from calendar");

# And execute the request
$sth.execute; 

# Fetch all the rows
my @arr = $sth.allrows;
say @arr;

# Finalise the statement and close the connection
$sth.finish;
$dbh.dispose;

There are several ways of fetching data. The one shown in the code is the $sth.allrows method that returns a list of lists with the data from the table.

Alternatively, rows can be read one by one using the $sth.row method. To get the row data in a hash, add the :hash attribute: $sth.row(:hash).

my $sth = $dbh.prepare("select what, when from calendar");
$sth.execute; 

my $row_hash = $sth.row(:hash);
say $row_hash;

With the insert statements, placeholders may be used to avoid the need of escaping the values before injecting them into the SQL query. In the following example, a new row will be written to the database table. The actual values are passed to the execute method.

my $sth = $dbh.prepare(
    "insert into calendar values (?, ?)"
);

$sth.execute('2017-01-01', 'Wake up');