69. Степени как индексы в Perl 6

В Perl 6 вы можете использовать юникодные символы цифр в суперскрипте, чтобы записать возведение в степень.

Например:

say 2⁵; # 32

С той же легкостью степень может быть больше девятой, то есть содержать больше одной цифры:

say 1.01¹³; 1.13809328043329

Более того, допустимы и отрицательные степени:

say 4⁻³; # 0.015625

Все это работает и с переменными. Например, проверим теорему Пифагора:

my $a = 3;
my $b = 4;
my $c = 5;

say $c² == $a² + $b²; # True

 

68. Типизированные хеши в Perl 6

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

my Int $i;

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

> my Int @i;
[]

> @i.push(42);
[42]

Если попытаться в этот массив добавить строку, произойдет ошибка:

> @i.push('Hello');
Type check failed in assignment to @i;
expected Int but got Str ("Hello")
  in block <unit> at <unknown file> line 1

А вот с хешами чуть сложнее, потому что у каждого элемента хеша два элемента: ключ и значение.

Чтобы указать тип значений, используется вот такой синтаксис:

my Str %s;

Теперь мы можем хранить строки:

> %s<Hello> = 'World'
World

> %s<42> = 'Fourty-two'
Fourty-two

Но не числа:

> %s<x> = 100
Type check failed in assignment to %s;
expected Str but got Int (100)
  in block <unit> at <unknown file> line 1

(Обратите внимание, что ключом в %s<42> тоже является строка, а не число.)

А чтобы указать тип ключей, поставьте его имя в фигурных скобках:

my %r{Rat};

У нас получился типизированный, или объектный хеш.

Например, создадим хеш, где ключами будут работать значения типа Rat:

> %r<22/7> = pi
3.14159265358979

> %r
{22/7 => 3.14159265358979}

Теперь уже невозможно использовать ни целые числа, ни строки:

> %r<Hello> = 1
Type check failed in binding to parameter 'key';
expected Rat but got Str ("Hello")
  in block <unit> at <unknown file> line 1

> %r{23} = 32
Type check failed in binding to parameter 'key';
expected Rat but got Int (23)
  in block <unit> at <unknown file> line 1

И, наконец, еще более ограничим элементы хеша, указав одновременно и тип ключей, и тип значений:

my Str %m{Int};

Ключи здесь — целые числа, а значения — строки. Например, в этом хеше теперь можно хранить соответствие номеров месяцев их названиям, но не наоборот:

> %m{3} = 'March'
March

> %m<March> = 3
Type check failed in binding to parameter 'key';
expected Int but got Str ("March")
  in block <unit> at <unknown file> line 1

 

67. Модификаторы (adverbs) в регексах Perl 6, часть 3

Осталось рассмотреть три модификатора: :r:ov и :ex.

:r или :ratchet

Запрет на бектрекинг. Сравните две попытки:

> 123 ~~ / \d+ 3/
「123」

> 123 ~~ m:r/ \d+ 3/
False

Несмотря на то, что сам по себе регекс подходит к числу 123, во втором случае класс \d+ захватил все цифры и отказывается уступать. Более реалистичный случай использования :r вы можете встретить в конструкциях с альтернативами |.

:ov или :overlap

Разрешает поиск с пересечениями. Если в одной позиции начинается более чем одна подходящая последовательность, то выбирается самая длинная. Например, найти все строки, начинающиеся с 1 и заканчивающиеся 2:

> 12345678913234 ~~ m:ov/ 1 .* 2 /
(「123456789132」 「132」)

> 12345678913234 ~~ m:ov/ 1 .*? 2 /
(「12」 「132」)

:ex или :exhaustive

Работает как :ov, но снимает ограничения на поиск самых длинных последовательностей. То есть этот модификатор найдет все:

> 12345678913234 ~~ m:ex/ 1 .* 2 /
(「123456789132」 「12」 「132」)

> 12345678913234 ~~ m:ex/ 1 .*? 2 /
(「12」 「123456789132」 「132」)

66. Модификаторы (adverbs) в регексах Perl 6, часть 2

Сегодня — продолжение обзора модификаторов регексов в Perl 6.

:p(N) или :pos(N)

Начать поиск с указанной позиции. Важно обратить внимание на то, что при использовании этого адверба (как их называть по-русски? наречия вроде не оч в тему, а название модификаторы было в Perl 5) регекс привязывается к этой позиции и не может пропустить другие символы перед тем, как совпасть.

> 'hello world' ~~ /l./
「ll」

> 'hello world' ~~ m:p(0)/l./
False

> 'hello world' ~~ m:p(1)/l./
False

> 'hello world' ~~ m:p(2)/l./
「ll」

Попробуем найти третье вхождение буквы l:

> 'hello world' ~~ m:p(8)/l./
False

> 'hello world' ~~ m:p(9)/l./
「ld」

:c или :continue

Продолжить с места предыдущего совпадения. Рассмотрим на примере с той же строкой:

> 'hello world' ~~ /l./
「ll」

> 'hello world' ~~ /l./
「ll」

> 'hello world' ~~ m:c/l./
「ld」

Аналогично :p, к :c можно добавить целочисленный аргумент, чтобы сместить начало матча в нужную позицию.

65. Модификаторы (adverbs) в регексах Perl 6, часть 1

В регексах Perl 6 по-прежнему есть модификаторы, однако они теперь выглядят и называются иначе. Называются они теперь adverbs (наречия) и ставятся после двоеточия не после, а до регекса.

Adverbs имеют короткое и длинное имена. Давайте посмотрим на имеющиеся предложения. Все приведенные ниже примеры показаны как часть диалога в режиме REPL.

:i или :ignorecase

Игнорирование регистра букв.

> 'Moscow' ~~ m:i/moscow/
「Moscow」
> 'Moscow' ~~ m/moscow/
False

:s или :sigspace

Включение режима значимости пробелов. В целом этот флаг противоположен по действию модификатору /x из Perl 5. По умолчанию пробелы в регексе считаются незначимыми.

> 'alpha beta' ~~ / a\S+ b\S+ /
Nil

> 'alpha beta' ~~ / a\S+ ' ' b\S+ /
「alpha beta」

> 'alpha beta' ~~ m:s/ a\S+ b\S+ /
「alpha beta」

:g или :global

Искать глобально (но без пересечения) и возвращать несколько результатов.

> 'text' ~~ /\w/
「t」

> 'text' ~~ m:g/\w/
(「t」 「e」 「x」 「t」)

 

64. Тернарный оператор в Perl 6

В Perl 6 по-прежнему присутствует тернарный оператор, но выглядит он теперь иначе:

my $var = -10;
my $abs = $var < 0 ?? -$var !! $var;
say $abs;

Остальное все понятно — оператор делает ровно то же, что и ? ! в Perl 5. Однако, при попытке написать по-старому, вы получите сообщение об ошибке:

$ perl6 ternary.pl 
===SORRY!=== Error while compiling /Users/ash/ternary.pl
Unsupported use of ? and : for the ternary conditional operator;
in Perl 6 please use ?? and !!
at /Users/ash/ternary.pl:2
------> my $abs = $var < 0 ?⏏ -$var : $var;

Интересно, что в самых первых реализациях Perl 6 тернарный оператор выглядел как ?? ::. На этот случай тоже предусмотрено сообщение:

$ perl6 ternary.pl 
===SORRY!=== Error while compiling /Users/ash/ternary.pl
Please use !! rather than ::
at /Users/ash/ternary.pl:2
------> my $abs = $var < 0 ?? -$var :⏏: $var;
 expecting any of:
 colon pair

 

63. Тип данных enum в Perl 6

В Perl 6 есть тип данных для создания перечислений — enum. Его использовать предельно просто:

enum colours <red yellow green>;

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

say red;
say green;

На печати появятся названия как они есть:

red
green

Если необходимы числовые значения, используйте метод Int:

say red.Int;    # 0
say yellow.Int; # 1
say green.Int;  # 2

По умолчанию отсчет ведется с нуля, но это можно изменить, указав нужное значение первому элементу перечисления:

enum colours (red => 10, 'yellow', 'green');

say red;        # red
say green;      # green
say yellow;     # yellow

say red.Int;    # 10
say yellow.Int; # 11
say green.Int;  # 12

Обратите внимание, что Perl 6 понял, что первое значение — это пара red => 10, а дальше идут две строки, которые он не попытался объединить в пару yellow => 'green'.

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

enum colours << :red(10) yellow green >>;

Разумеется, можно присвоить свои значения каждому элементу:

enum colours (red => 10, yellow => 20, green => 30);

say red.Int;    # 10
say yellow.Int; # 20
say green.Int;  # 30