46. Цитирующие скобки в Perl 6

С помощью угловых цитирующих скобок в Perl 6 очень удобно создавать массивы со строками. В Perl 5 похожий механизм давало слово qw.

my @names = <alpha beta gamma>;
.say for @names;

Вы должны сами определиться с тем, ставить ли пробелы после открывающей и перед закрывающей скобкой. Часто можно видеть вот такой вариант:

my @names = < alpha beta gamma >;

В этом случае в массив попадут ровно те же три элемента.

Perl 6 считает разделителем между отдельными элементами все пробельные символы (whitespace), поэтому данные могут содержать, например, дефисы или точки:

my @nums = < . - 10 20.30 -40 >;

Здесь надо быть осторожным и учитывать, что тип данных может оказаться не совсем тем, что вы предполагаете. Давайте посмотрим на это:

my @nums = < . - 10 20.30 -40 >;
for @nums {
    say "{$_.^name} $_";
}

Программа печатает следующее:

Str .
Str -
IntStr 10
RatStr 20.30
IntStr -40

Комментарии (ни обычные, ни embedded) внутри цитирующих скобок не работают. Возьмем программу:

my @data = <
    # comment?
    data_load 
>;
.say for @data;

В массиве окажется три элемента:

#
comment?
data_load

45. Численные методы и Perl 6

Вчера в группе Perl 6 на Фейсбуке Solomon Foster показал вот такой пример:

my @x = FatRat.new(1, 1), 
        -> $x { $x - ($x ** 2 - $N) / (2 * $x) } ... *;

В этом коде в одну строку реализован численный метод вычисления квадратного корня (методом Ньютона).

Давайте возьмем какое-то понятное число $N и посмотрим значение его корня на десятой итерации:

10.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000114617269858815597676188906948935679812072077815172636665039841545242611088386175405939458945274038752495996921868425893616324912131911758516481924280284021811361729487444582731688466773998426538733 . . .

Я показал только часть результата, в реальности цифр еще пять раз по столько же.

Что здесь примечательного?

Во-первых, тип FatRat — это дроби с произвольно большими числителем и знаменателем. Если использовать Rat, то мы довольно быстро придем к обычным числам с плавающей точкой.

Во-вторых, оператор последовательности вместе с встроенным генератором — отличный способ программировать подобные численные методы без организации циклов. Конечно, надо еще придумать, как остановиться при достижении нужной точности, но тем не менее, то что есть, уже выглядит довольно экспрессивно.

44. Транспонирование матрицы в Perl 6

В Perl 6 есть метаоператор Z, который объединяет два списка как застежка на молнии, по очереди перемежая элементы. Мы, возможно, рассмотрим его как-нибудь отдельно, но сегодня я хочу показать, как этот оператор магически транспонирует матрицу.

Берем двумерную матрицу:

my @matrixA = [1, 2],
              [3, 4];

Если хочется, можно поставить еще одни скобки:

my @matrixA = [[1, 2],
               [3, 4]];

И теперь в одно действие транспонируем:

my @matrixB = [Z] @matrixA;

Метаоператор Z здесь поставлен внутрь оператора редукции. Вуаля, матрица транспонировалась:

[(1 3) (2 4)]

43. Массивы как аргументы функций в Perl 6

В Perl 6 передавать массивы функциям одно удовольствие. Достаточно объявить массив в сигнатуре, и Perl поймет, что с этим делать дальше. В том числе, если дальше идут, например, скаляры.

sub f($a, @b, $c) {
    say "a = $a";
    say "b = @b[]";
    say "c = $c";
}

my @arr = <5 7 9>;
f(10, @arr, 20);

Легко видеть, что все аргументы передались как следует, без перемешивания:

a = 10
b = 5 7 9
c = 20

Очень удобно, если сравнивать с Perl 5.

Но теперь возникает другой вопрос: а как передать переменное число скалярных величин так, чтобы они все оказались в одном массиве? Ответ: с помощью звездочки, которая создает так называемый slurpy-параметр.

sub g(*@data) {
    say @data;
}

g(3, 5, 7);

Эта программа работает правильно:

[3 5 7]

А вот если не поставить звездочку, то возникнет ошибка, поскольку ожидается один массив, а получены три скаляра:

===SORRY!=== Error while compiling sub-slurpy.pl
Calling g(Int, Int, Int) will never work with declared signature (@data)
at sub-slurpy.pl:5
------> <BOL>⏏g(3, 5, 7);

42. Фейзеры ENTER и LEAVE в Perl 6

Блоки, которые помечаются большими буквами, в Perl 6 называются фейзерами (phasers). Вы знакомы с ними по Perl 5, например: BEGIN и END.

Сегодня мы рассмотрим два фейзера, которые выполняются при входе в подпрограмму и при выходе из нее: ENTER и LEAVE. В следующем примере это наглядно видно:

sub f() {
   ENTER say 'Hi';
   LEAVE say 'Bye';

   say 'Body';
}

f;

Программа печатает такие строки:

Hi
Body
Bye

То есть сначала выполняется блок ENTER, затем тело функции и наконец блок LEAVE.

Порядок выполнения фейзеров не зависит от того, где они расположены. Например, все работает даже после return:

sub f() {
    say 'Body';
    return;

    LEAVE say 'Bye';
    ENTER say 'Hi';
}

При наличии более одного фейзера того же типа, блоки ENTER выполняются в порядке объявления, а LEAVE в противоположном:

sub f() {
    say 'Body';

    ENTER say 'Hi 1';
    ENTER say 'Hi 2';

    LEAVE say 'Bye 1';
    LEAVE {
        say 'Bye 2';
    }
}

f;

(Здесь одновременно показан пример с блоком кода в одном из фейзеров.)

Программа печатает строки в следующем порядке:

Hi 1
Hi 2
Body
Bye 2
Bye 1

41. Передача именованных аргументов в Perl 6

Функции (и методы классов) в Perl 6 способны принимать именованные параметры. Простейший способ — разделить имя и значения стрелкой:

sub f(:$a, :$b) {
    $a ** $b
}

say f(a => 2, b => 3); # 8

Но возможен и другой синтаксис, с помощью двоеточия. Существует несколько основных разновидностей.

:key(value)

Все начинается с двоеточия, а значения стоят в скобках:

say f(:a(2), :b(3));

Вместо круглых скобок допустимы, например, угловые:

say f(:a<2>, :b<3>);

:Nkey

Для целочисленных величин предусмотрен еще вот такой странный синтаксис:

say f(:2a, :3b);

:key и :!key

Если именованные параметры используются как флаги, то значения указывать не обязательно. В этом случае передать True и False можно следующим образом:

sub g(:$key) {
    $key
}

say g(:key);  # True
say g(:!key); # False

Пары

Фактически, все показанные варианты создают пары ключ — значение, поэтому таким же образом можно поступить при создании хешей, например:

my %data = :alpha(10), :beta(20), :gamma(30);
say %data<beta>; # 20

40. Предопределенные символьные классы в регексах Perl 6

Давайте сегодня посмотрим символьные классы, которые доступны в регексах Perl 6.

Прежде всего, шпаргалка о том, как матчить строку:

'string' ~~ /str/;

Сегодня рассмотрим символьные классы, которые записываются с обратным слешем. Часть из них совпадает с тем, что есть в Perl 5.

Белое на белом

Существует несколько классов, совпадающих с разными видами пробельных символов:

\s — любой пробельный символ, как горизонтальный, так и вертикальный;

\h — горизонтальный пробел (например, пробел или табуляция);

\v — вертикальный пробел (например, перевод строки);

\n — перевод строки;

\t — табуляция.

Обратите внимание, как работают символы при сравнении с переводом строки:

say 1 if "\n" ~~ /\s/; # 1
say 2 if "\n" ~~ /\v/; # 2
say 3 if "\n" ~~ /\h/; # не совпало

Ко всем классам существуют комплиментарные, которые записываются с большой буквой: \S, \H, \V, \N и \T — все они совпадают с соответствующими типами не-пробелов.

Черное на белом

Пара символьных классов, совпадающих с конкретными наборами символов:

\d — цифры (не только ASCII, но и все юникодные).

\w — символы, которые могут быть в словах — буквы, цифры и символ подчеркивания.

Классы с противоположным смыслом:

\D — не цифры;

\W — не то, из чего состоят слова.