3. Мультифункции для рекурсии в Perl 6

Perl 6 — мультипарадигменный язык. Это означает, что на нем можно писать в разных стилях, как минимум в процедурном, в ООП- и в функциональном.

Сегодня мы посмотрим, как можно организовать рекурсию для простейшей задачи — печати чисел от 1 до 10.

Сразу оговоримся, что простейшее решение этой задачи такое:

.say for 1..10;

Но на этом примере попробуем понять, как задействовать механизмы Perl 6, чтобы сделать рекурсивный код.

Самое примитивное — вызвать функцию из самой себя и в нужный момент остановиться; здесь нет ничего нового:

gen-number(1, 10);

sub gen-number($current, $maximum) {
    say $current;
    gen-number($current + 1, $maximum) if $current < $maximum;
}

Возможно, стоит отметить, что если выбран функциональный стиль программирования, то следует отказаться от явного изменения переменных, так что следующий вариант (идеологически) не подходит:

my $current = 1;
my $maximum = 10;

while $current <= $maximum {
    say $current;
    $current++; # $current = $current + 1
}

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

gen-number(1, 10);

multi sub gen-number($current, $maximum) {
    say $current;
    gen-number($current + 1, $maximum);
}

multi sub gen-number($current, $maximum where {$current == $maximum}) {
    say $current;
}

Функция gen-number теперь объявлена мультифункцией. Второй вариант ограничивает свои аргументы: они должны быть равны, чего требует условие со словом where. Поэтому в первых девяти случаях будет вызван первый вариант, и только когда $current сравняется с $maximum, сработает второй вариант функции, которая лишь печатает значение, но не продолжает рекурсию.

2. Что такое мультифункции в Perl 6

В Perl 6 есть ключевое слово multi, которое создает так называемые мультифункции (multi-subs). Это ни что иное как множественная диспетчеризация (multiple dispatch), встроенная в язык.

В отличие от обычных функций, которые объявляются со словом sub, мультифункции требуют двух слов: multi sub. Имя функции при этом остается одним и тем же для всего набора мультифункций. В зависимости от выполненных условий, компилятор выбирает один из вариантов функции.

Число аргументов

Рассмотрим несколько примеров. Первый пример — вычисление расстояния от начала координат до точки на прямой, на плоскости или в трехмерном пространстве.

multi sub dist($x) {
    return $x;
}

multi sub dist($x, $y) {
    return sqrt($x ** 2 + $y ** 2);
}

multi sub dist($x, $y, $z) {
    return sqrt($x ** 2 + $y ** 2 + $z ** 2);
}

say dist(2);        # 2
say dist(3, 4);     # 5
say dist(8, 9, 12); # 17

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

Типы аргументов

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

multi sub mirror(Int $i) {
    -$i
}

multi sub mirror(Str $s) {
    $s.flip
}

say mirror(42);   # -42
say mirror('42'); # 24

Здесь функция возвращает должна вернуть «зеркальный» вариант своего аргумента, чтобы это ни значило. Точный смысл вы в праве установить самостоятельно для каждого типа аргумента. Для целых чисел (Int $i) это будет противоположное число, а для строки (Str $s) — строка, записанная в обратном порядке.

Точно так же возможно определить свой класс и дополнить мультифункцию соответствующим вариантом. Во-первых, определим класс для светофора, у которого есть текущее значение value. Во-вторых, создадим мультифункцию, которая ожидает такой объект и инвертирует его:

class TrafficLight {
    has Str $.value;
}

multi sub mirror(TrafficLight $obj) {
    $obj.value eq 'red' ?? 'green' !! 'red'
}

say mirror(TrafficLight.new(value => 'green')); # red

Ограничение на значение аргументов

Еще один вариант — выбор одной из мультифункций, опираясь на значение аргументов. Для простоты рассмотрим простейший вариант функции с одним аргументом, которая для коротких слов печатает предупреждение о том, что пароль слишком короткий:

multi sub set-password($pwd) {
    say "Password '$pwd' is OK"
}

multi sub set-password($pwd where {$pwd.chars <= 5}) {
    say "Password '$pwd' is too short!"
}

set-password('He11oW0rld!'); # OK
set-password('qwert');       # too short!

Во втором варианте функции значение аргумента уточняется с помощью ключевого слова where:

multi sub set-password($pwd where {$pwd.chars <= 5}) { . . . }

Эта функция будет вызвана только в том случае, если выполняется условие $pwd.chars <= 5, то есть когда строка недостаточно длинна.

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

На сегодня все. Завтра будем использовать мультифункции для создания рекурсии.

1. Ресурсы про Perl 6

Давайте начнем новый сезон с того, что посмотрим, где сейчас идет движуха по поводу шестого перла.

Язык

Во-первых, есть официальная точка входа — сайт perl6.org.

Screen Shot 2017-12-31 at 12.24.53.png

Один из самых ценных разделов на этом сайте — документация (docs.perl6.org), содержащая достаточно подробное описанием синтаксиса, встроенных функций и классов. Иногда документации недостаточно, но почти всегда можно найти примеры использования описываемых языковых конструкций.

Screen Shot 2017-12-31 at 12.27.30.png

Софт

Следующий важный сайт — rakudo.org. Rakudo (или полностью — Rakudo Perl 6) — это лучшая (да, в целом, просто единственная) на сегодня полноценная реализация компилятора. За последние два-три года Ракудо радикально улучшился — перестал падать и стал работать достаточно быстро (об этом мы еще поговорим отдельно).

Если вы не собираетесь исследовать внутренности компилятора, а хотите просто загрузить компилятор, идите прямиком на страницу загрузки Rakudo Star — это набор, состоящий из компилятора, виртуальной машины и еще нескольких полезных модулей и утилит.

Screen Shot 2017-12-31 at 12.28.38.png

Текущий аналог CPAN для Perl 6 — утилита zef (она идет вместе с Rakudo Star) и сайт modules.perl6.org.

Screen Shot 2017-12-31 at 12.36.33.png

Попробовать Perl 6 без загрузки и установки компилятора можно и в онлайне на странице glot.io/new/perl6.

Screen Shot 2017-12-31 at 12.41.07

Люди

В социальной сфере у шестого перла два основных места встречи. Из современного — группа Perl6 на Фейсбуке.

Screen Shot 2017-12-31 at 12.55.25.png

Из прошлой эпохи — IRC-канал #perl6. Я однозначно рекомендую присоединиться к фейсбучной группе, а вот по поводу IRC решайте сами — там, конечно, можно найти интересное или задать вопросы, но при этом много разговоров, которые могут быть не особо интересными.

Что читать в онлайне

Есть сайт pl6anet.org — RSS-агрегатор блогов и сайтов про Perl 6. Ссылки с него появляются и на главной странице perl6.org.

Раз в неделю выходит выпуск Perl 6 Weekly — обзор основных событий за неделю, выходящий обычно вечером по понедельникам. Этого вполне достаточно, чтобы быть в курсе дел.Screen Shot 2017-12-31 at 13.07.06

Если вам интересно следить за деталями разработки компилятора, подпишитесь на рассылки perl6-compiler@perl.org и perl6-language@perl.org. Еще несколько списков вы найдете на странице perl6.org/community в разделе Mailing Lists.

Буквально на днях, видимо как реакция на бурный срачик по поводу изъятия из Perl 5 ключевого слова when, что ломало обратную совместимость, появился ресурс alerts.perl6.org, где на сегодня висит пока единственный алерт про изменение имени метода .parse-names → .uniparse в следующей версии Perl 6.d.

Раз в год, с 1 по 24 или 25 декабря, выходят ежедневные статьи в Perl 6 Advent Calendar. Календарь только что закончился, следующий выход примерно через год, так что не постесняюсь дать ссылку на свой английский блог Perl 6 Inside Out, где я рассказываю о внутреннем устройстве Rakudo Perl 6.

Screen Shot 2017-12-31 at 13.21.26

На perl6.ru тоже заходите 🙂

Книги

Наконец, для офлайнового образования — читайте книги. В 2017 году вышло несколько книг на разный вкус, и еще несколько уже запланировано на 2018-й. Все книги по современному Perl 6 перечислены на странице allperlbooks.com/tag/perl6.0.

Screen Shot 2017-12-31 at 14.06.36.png

На сегодня это все, ждем вас завтра!

0. Третий сезон perl6.ru

Добро пожаловать на третий сезон perl6.ru!

Я начал вести блог perl6.ru в конце 2003 года, когда Perl 6 только зарождался, и все ждали его появления через год-два. Во второй раз закинул рыбак, когда от первого впечатления мало что осталось, но опять же, была надежда, что вот-вот уже будет можно.

Screen Shot 2017-12-31 at 00.11.26

И когда уже ничего не предвещало выхода шестого перла, в декабре 2015 года началась новая эра — спецификация устаканилась, а Rakudo стал работоспособным и перестал падать.

Предыдущие сезоны сайта доступны на веб-архиве — завораживающее зрелище; если вы не были, рекомендую полистать выцветшие страницы десяти-пятнадцатилетней давности.

1 января и в понедельник, я начинаю третий сезон. В этот раз хочется сделать ежедневные выпуски, которые будут появляться в 18 часов по Москве. Формат, кроме времени выхода, ничем не ограничен. Это будут и новости о том, что происходит с перлом, и рассказы об интересных особенностях языка, и что-нибудь еще, что придумается по ходу дела. В планах продержаться год, а дальше будет видно.

Поздравляю всех с Новым 2018-м годом и желаю вам приятного чтения!