Interested Article - Raku

Raku (от яп. 楽土 , произн. ракудо Рай , и от , произн. раку — счастье, лёгкость, сукха ) — язык программирования из семейства Perl -подобных языков. Серьёзный пересмотр как дизайна, так и реализации языка Perl, нарушающий обратную совместимость с ним, хотя до 2010 года еще предполагалось наличие режима совместимости.

Подобно языку Perl, Raku оставляет программистам много свободы . Он всё еще позволяет выражаться кратко, в том числе писать однострочники, но также упрощает и написание больших программ, благодаря статической типизации и улучшенной поддержке ООП .

Прежнее название Raku — Perl 6. В течение многих лет в сообществе Perl имели место шуточные замечания о дате релиза. На вопрос «когда выйдет Perl 6» обычным ответом было «на Рождество», но без указания года. В 2015 году, то есть после пятнадцати лет ожидания, наконец была анонсирована так называемая «рождественская» версия.

История

В Perl 6 мы решили, что лучше исправить язык, чем исправлять пользователя. Ларри Уолл

Разработка Perl 6 была впервые анонсирована Ларри Уоллом 19 июля 2000 года, в четвертый день Perl Conference того года, в его выступлении State of the Onion . В то время первоочередными задачами было: удалить из языка «исторические бородавки»; «простые вещи должны оставаться простыми, сложные вещи должны становиться проще, и невозможные вещи должны стать сложными»; общая чистка внутреннего дизайна и API . Процесс начался с серии RFC . Этот процесс был открыт для всех участников, и ни один аспект языка не оставался закрытым для изменений.

Был получен 361 запрос, каждый из которых был рассмотрен Уоллом. Затем он начал процесс написания нескольких «Апокалипсисов» — христианский термин, означающий «раскрытие хороших новостей хорошим людям». Хотя первоначальной целью было написать по одному Апокалипсису для каждой главы книги , стало очевидно, что по мере написания каждого Апокалипсиса, предыдущие Апокалипсисы аннулировались более поздними изменениями. По этой причине был опубликован набор Синопсисов, каждый из которых относился к одному Апокалипсису, но включал корректировки из новых Апокалипсисов. Сегодня спецификация Raku управляется набором тестов «roast», в то время как Синопсисы хранятся в качестве исторической справки.

Есть также серия Экзегез, написанных , которые объясняют содержание каждого Апокалипсиса с точки зрения практического использования. Каждая Экзегеза состоит из примеров кода с обсуждением их использования и значения.

Первоначальные цели и последствия

Основной целью, которую Уолл предложил в своей первоначальной речи, было удаление «исторических бородавок». К ним относилась путаница в сигилах массивов и хэшей, неоднозначность функций select , проблемы с использованием голых (без пунктуации ) файловых дескрипторов. Уолл также упомянул в своей речи много других проблем, решение которых Perl-программисты обсуждали годами. [ источник не указан 884 дня ]

Последствием этих целей стала потеря обратной совместимости. Поскольку обратная совместимость обычно подразумевается при улучшении программного обеспечения, ломающие её изменения в Perl 6 должны были быть явно сформулированы. Постепенно различие между Perl 5 и Perl 6 стало настолько большим, что 12 октября 2019 года Perl 6 был переименован в Raku.

За прошедшие годы вектор развития Raku менялся несколько раз. Введение концепций из Python и Ruby было ранним влиянием. Кроме того, Pugs, первый интерпретатор Raku, написан на функциональном языке Haskell , и многие элементы функционального программирования были впитаны командой разработчиков Raku.

Маскот

Ларри Уолл на фоне бабочки Камелии — талисмана Perl 6

Маскот языка — насекомое Камелия. Его имя — отсылка к эмблеме языка Perl, верблюду («Camel»), а его форма, в традициях любящего каламбуры сообщества Perl, перекликается со словом « bug ». Спиральные узоры, вписанные в его крылья, похожие на крылья бабочки, напоминают символы «P6», а расходящееся косоглазие — это преднамеренный каламбур с выражением «Wall-eyed».

Одна из целей живого и красочного дизайна логотипа заключалась в том, чтобы препятствовать мизогинии в сообществе и дать возможность людям с «мужскими убеждениями» показать свою чувствительную сторону.

Реализации

Rakudo — наиболее развитая реализация, что не делает её официальной версией языка, т.к. язык определяется не реализацией, а набором тестов.

Rakudo позволяет выполнять код в виртуальных машинах MoarVM, JVM и на платформе Node.js . MoarVM — виртуальная машина, созданная специально для Rakudo и компилятора NQP. Компилятор NQP (Not Quite Perl 6, с англ. «не совсем Perl 6») реализует подмножество языка, включающее для разбора исходного кода, работы с абстрактным синтаксическим деревом и бэкенд-специфичной кодогенерацией . Значительная часть Rakudo написана на Raku и NQP. Rakudo — не самодостаточный компилятор, и в данный момент раскрутка компилятора не планируется.

После версии «2015.02», в Rakudo была прекращена поддержка виртуальной машины Parrot (предшественницы MoarVM), создающейся исходя из ошибочного предположения, что Perl 6 будет похож на Perl 5.

Исторические реализации

Первой реализацией Raku был Pugs интерпретатор и компилятор, написанный на Haskell . Был самой продвинутой реализацией, однако с 2007 года вносились только минимальные исправления для соответствия новым версиям GHC , и по состоянию на ноябрь 2014 года Pugs не поддерживается. В августе 2006 года разбил файлы тестов Pugs на фрагменты, прикрепив к ним соответствующие параграфы Синапсисов, а в январе 2008 года эти тесты были интегрированы в официальные тесты языка («roast»). В феврале 2015 года сообщество объявило тесты языка его спецификацией.

  • « » — компилятор из Perl 6 в байт-код виртуальной машины « Common Language Runtime » (CLR);
  • « » — компилятор, написанный на языке Perl 6 реализации «Rakudo».

Основные отличия от Perl

Raku и Perl отличаются фундаментально, хоть в основном и было намерение оставить Raku Perl'овым. Большая часть изменений предназначена для нормализации языка, чтобы его было легче понять как новичкам, так и опытным программистам, и сделать «простые вещи проще, а сложные — более возможными».

Спецификация

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

Система типов

В Raku динамическая система типов была дополнена статическими типами . Например:

my Int $i = 0;
my Rat $r = 3.142;
my Str $s = "Hello, world";

Однако, статические типы остаются опциональными, так что программисты могут делать большую часть вещей без явного указания типов.

my $i = "25" + 10; # $i is 35

Список формальных параметров подпрограмм

В Perl у подпрограмм нет формальных параметров , хоть простая проверка количества и типов параметров возможна с помощью прототипов подпрограмм. Вместо этого, фактические параметры, передаваемые по ссылке, прячутся за элементами массива @_ в теле подпрограммы.

В Raku появляются настоящие формальные параметры. Например:

sub do_something(Str $thing, Int $other) {
    ...
}

Также, как в языке Perl, в Raku параметры передаются по ссылке, но по умолчанию в Raku они константны , т.е. значения в них не могут быть изменены. Они могут быть явно объявлены как позволяющие менять оригинальное значение ( is rw ) или как копии ( is copy ), что эквивалентно передаче по значению.

Способы передачи параметров

В Raku три способа передавать параметры: позиционный, именованный и хлюпающий (slurpy).

Позиционные параметры — это обычный упорядоченный список, как в большинстве языков программирования. Даже они могут быть переданы в произвольном порядке, если указывать их имена. Параметры же, которые могут быть переданы только по имени, обозначаются символом : перед сигилом формального параметра. Хлюпающие параметры — это способ создавать вариативные функции в Raku. Они обозначаются символом * перед сигилом формального параметра. Slurpy-хэш будет захватывать неупомянутые при объявлении подпрограммы именованные параметры, а slurpy-массив — последующие позиционные фактические параметры.

В следующем примере присутствуют все три способа, включая slurpy-массив.

sub somefunction($a, $b, :$c, :$d, *@e) {
    ...
}

somefunction(1, 2, :d(3), 4, 5, 6); # $a=1, $b=2, $d=3, @e=(4,5,6)

Позиционные параметры по умолчанию обязательны, если только после имени параметра не стоит вопросительный знак. Именованные же параметры по умолчанию наоборот опциональны, если только после имени не стоит восклицательный знак. Хлюпающие параметры опциональны всегда.

Блоки и замыкания

Параметры также могут быть переданы в любые блоки кода, которые ведут себя как замыкания . В частности, например, тела циклов for и while являются замыканиями. В следующем примере цикл берёт из списка по три элемента за раз и передаёт их в блок как переменные $a , $b и $c .

for @list -> $a, $b, $c {
    ...
}

Это называется «pointy sub» или «pointy block», и стрелка в нём ведёт себя примерно как ключевое слово sub , вводя анонимное замыкание (или анонимную подпрограмму в терминологии Perl).

Инвариантность сигилов

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

# Perl-код
my @array = ('a', 'b', 'c');
my $element = $array[1];    # возвращает 'b',
my @extract = @array[1, 2]; # возвращает ('b', 'c')
my $element = @array[1];    # возвращает 'b' с предупреждением (с версии 5.10)

В Raku же сигилы инвариантны: как у массива, так и у элемента массива будет один и тот же сигил.

# Raku-код
my @array = 'a', 'b', 'c';
my $element = @array[1];    # в $element записывается 'b'
my @extract = @array[1];    # в @extract записывается ('b')
my @extract = @array[1, 2]; # в @extract записывается ('b', 'c')

Изменчивость сигилов в Perl вдохновлена согласованием числа в английском и многих других естественных языках .

"Это яблоко."                    # $a        верно
"Эти яблоки."                    # @a        верно
"Это третье яблоко."             # $a[3]     верно
"Эти третье яблоко."             # @a[3]     не верно

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

# Perl-код: получение массива из элемента хэша.
# В этом хэше хранятся хэши, содержащие массивы.
my @trans_verbs = @{ $dictionary{ 'verb' }{ 'transitive' } };

Подобные конструкции не имеют аналогов в распространённых естественных языках, что вызывает высокую когнитивную нагрузку при написании кода. Тот же код на языке Raku:

# Raku-код: получение массива из элемента хэша.
# В этом хэше хранятся хэши, содержащие массивы.
my @trans_verbs = %dictionary<verb><transitive><>;

Объектно-ориентированное программирование

В языке Perl объектно-ориентированное программирование поддерживается через функцию bless , превращающую любую переменную в объект определенного класса, у которого становятся доступными для вызова методы , объявленные в классе.

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

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

class Point is rw {
    has $.x;
    has $.y;
    
    method distance( Point $p ) {
        sqrt(($!x - $p.x) ** 2 + ($!y - $p.y) ** 2)
    }
    
    method distance-to-center {
        self.distance: Point.new(x => 0, y => 0)
    }
}

my $point = Point.new( x => 1.2, y => -3.7 );
say "Позиция точки: (", $point.x, ', ', $point.y, ')';
# Позиция точки: (1.2, -3.7)

# Изменение x и y (используются методы "x" и "y"):
$point.x = 3;
$point.y = 4;
say "Позиция точки: (", $point.x, ', ', $point.y, ')';
# Позиция точки: (3, 4)

my $other-point = Point.new(x => -5, y => 10);
$point.distance($other-point); #=> 10
$point.distance-to-center;     #=> 5

В Perl методы вызываются с помощью стрелки: $object->method() . В Raku вместо стрелки используется точка, как во многих других языках (например, Java и Python).

В терминологии Raku $.x называется атрибутом. Метод, используемый для доступа к атрибуту называется аксессором (от англ. access — доступ). Он создаётся автоматически (при объявлении атрибута через точку ) и называется так же, как атрибут. Он работает как геттер и, когда класс или атрибут is rw , приобретает свойства сеттера и может использоваться в левой части присваивания. Вместо автоматических аксессоров, программист может определить свои нестандартные методы. Также, в теле класса ко всем атрибутам, вне зависимости от того, как они объявлены, можно обратиться напрямую, используя синтаксис $! .

Наследование, роли и классы

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

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

Роли в Raku берут на себя функцию интерфейсов в Java, примесей в Ruby, трейтов в PHP и Squeak (диалекте языка Smalltalk ). Они похожи на классы, но обеспечивают более безопасный, чем наследование, механизм композиции, предотвращающий конфликты имён атрибутов и методов. Роли не встраиваются в цепочку наследования. Роли относятся к номинальной системе типов (см. ), а не структурной, которая применяется, например, в Go . Они предоставляют семантические названия наборов поведений и состояний. Фундаментальное различие между ролями и классами в том, что роли не инстанцируют объекты.

Хоть роли и отличаются от классов, возможно написать код, создающий объект из роли. Попытка использовать роль для создания объекта приведёт к созданию класса с тем же именем. В документации Raku этот механизм назван автоматическим каламбурированием ролей, т.к. сгенерированный класс является каламбуром.

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

Например, собака — это млекопитающее , потому что собаки наследуют у млекопитающих некоторые черты, такие как молочные железы и, через их предков позвоночных , позвоночник . С другой стороны, собаки могут обладать разными типами поведения, которые могут меняться со временем. Например, собака может быть домашней, бродячей, быть поводырём . Эти наборы дополнительных поведений могут быть добавлены к собаке. Можно описать их таким образом, чтобы можно было их применять по отношению к другим животным. Например, кошка может быть домашней и бродячей. Собака и кошка отличаются друг от друга, но остаются в общей категории млекопитающих. Итак, Млекопитающее — это класс, Собака и Кошка — классы, унаследованные от млекопитающего. Но вышеназванные поведения — это роли, которые можно добавить в классы или объекты, созданные из классов.

class Млекопитающее is Позвоночное {
    ...
}
class Собака is Млекопитающее {
    ...
}
role Питомец {
    ...
}
role Бездомный {
    ...
}
role Поводырь {
    ...
}

Роли добавляются к классам и объектам с помощью ключевого слова does . Для наследования же используется ключевое слово is . Эти слова отражают различие в смысле этих возможностей языка: присоединение роли наделяет класс поведением роли, но не означает, что этот класс становится буквально тем же самым , что и эта роль.

class СобакаПоводырь is Собака does Поводырь {
    ...
}   # Подкласс присоединяет роль.

my $собака = Собака.new();
$собака does Поводырь;       # Объект присоединяет роль.

И роли, и классы являются типами. Роль может быть использована в объявлении переменной. Например, роль Незрячий может содержать атрибут типа Поводырь , в котором может быть собака-поводырь, лошадь-поводырь, человек-поводырь или даже машина-поводырь.

class Человек {
    has Собака $собака;     # Может содержать любой вид собаки —
    ...                     # не важно, Поводырь это или нет.
}

role Незрячий {
    has Поводырь $поводырь; # Может содержать любой объект с ролью
    ...                     # Поводырь — не важно, Собака это или нет.
}

Регулярные выражения

Регулярные выражения и обработка строк всегда были одними из определяющих особенностей Perl. Поскольку шаблоны Perl в определенный момент превзошли возможности регулярных выражений, документация Raku называет их просто регексами , дистанцируясь от формального определения регулярных выражений.

Raku расширяет набор функций Perl в отношении регулярных выражений, вкладывая их в бо́льший фреймворк для создания парсеров , называемый правилами . Правила предоставляют возможности контекстно-зависимого разбора (такие как из PEG и ANTLR ) и ведут себя как замыкания относительно своих лексических областей видимости . Правила вводятся с помощью ключевого слова rule , использование которого похоже на определение подпрограммы. Анонимные же правила могут быть введены с помощью ключевого слова regex (или rx ), или их можно описывать как регулярные выражения в Perl — с помощью операторов m (сопоставление) или s (замена).

В Апокалипсисе 5 Ларри Уолл перечисляет 20 проблем текущей «культуры использования регулярных выражений». В числе прочего, регулярные выражения Perl были «слишком компактными и „милыми“», они «слишком надеялись на слишком небольшой набор специальных символов», у них была «слабая поддержка именованного захвата», «слабая поддержка грамматик» и «плохая интеграция с языком».

Синтаксические упрощения

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

if is-true() {
    for @array {
        ...
    }
}

Оператор , (запятая) теперь является конструктором списков, поэтому скобки вокруг списков не требуются.

@array = 1, 2, 3, 4;

Цепочки сравнений

Raku разрешает следующие выражения:

if 20 <= $temperature <= 25 {
    say "Температура в комнате — от 20 до 25 градусов!"
}

Это воспринимается как последовательные сравнения слева направо с последующим объединением через логическое И .

Ленивые вычисления

Raku использует технику ленивых вычислений списков подобно некоторым функциональным языкам, таким как Haskell :

@integers = 0..Inf; # целые числа от нуля до бесконечности

Этот код не выдаст ошибку, пытаясь поместить бесконечный список в массив @integers , и не зависнет, пытаясь бесконечно увеличивать список, если запрашиваться будет конечное число элементов.

Это упрощает многие распространенные в Raku задачи, в том числе операции ввода-вывода, трансформации списков и передачу параметров.

Возможно также создание ленивых списков с помощью ключевых слов gather и take . Они похожи на генераторы в языках Icon и Python .

my $squares = lazy gather for 0..Inf {
    take $_ * $_;
};

Здесь $squares — это бесконечный список квадратов натуральных чисел (включая ноль), но благодаря ленивой природе этого списка, элементы вычисляются только тогда, когда к ним происходит доступ.

Скрещения

Raku вводит концепцию скрещений ( англ. junction — соединение, место пересечения; в Raku этот термин имеет также отношение к конъюнкции и дизъюнкции ). Это суперпозиция нескольких значений. В простейшем виде, скрещение создаётся операторами скрещения:

# Пример скрещения типа | ("any"):
my $color = 'белый';
unless $color eq 'белый' | 'чёрный' | 'серый' {
    die "Печать этим цветом не поддерживается.\n";
}

# Пример скрещения типа & ("all"):
my $password = 'secret!123';
if $password ~~ /<:alpha>/ & /<:digit>/ & /<:punct>/ {
    say "Ваш пароль достаточно надёжен.";
}

Оператор | выражает значение равное либо левому, либо правому аргументу, оператор & — одновременно и левому, и правому. Эти значения могут быть использованы в коде везде, где по смыслу предполагается одно значение. Любые операции со скрещением действуют одновременно на все его составляющие, и результат объединяется через оператор этого скрещения. Так, ("apple"|"banana") ~ "s" вернёт "apples"|"bananas" . Однако в булевом контексте скрещения возвращают лишь одно значение — истину или ложь: any возвращает истину, если сравнение истинно для хотя бы одного элемента; all возвращает истину, если сравнение истинно для всех элементов.

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

subset Color of Any where RGB_Color | CMYK_Color;
sub get_tint(Color $color, Num $opacity) {
    ...
}

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

Макросы

В низкоуровневых языках, макросы стали синонимом текстовой замены в исходном коде из-за ассоциаций с препроцессором языка Си . Однако в высокоуровневых языках, таких как Лисп , который появился раньше Си , макросы были более мощными. Этой лиспоподобной концепцией макросов Raku и воспользовался. Мощность этого типа макросов базируется на оперировании программой как высокоуровневой структурой данных , а не текстом, и на доступе ко всем возможностям языка.

Определение макроса в Raku выглядит подобно определению подпрограммы или метода. И оперировать такой макрос может и исходным кодом, и абстрактным синтаксическим деревом , и комбинацией этих двух вещей.

macro hello($what) {
    quasi { say "Hello { {{{$what}}} }" };
}

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

Идентификаторы

В Raku идентификаторы, помимо букв, цифр и подчеркиваний, могут также содержать апострофы и дефисы, при условии, что после них обязательно идут буквы. Буквы включают «соответствующие» (какие — зависит от реализации) символы Юникода , которые в Rakudo и MoarVM определены как все символы Юникода категории «L».

Использование дефисов вместо подчеркиваний называется « kebab case».

Метаоператоры

Метаоператоры — операторы, параметризующиеся другими операторами, подобно тому, как функции могут принимать другие функции в качестве параметров.

Метаоператор присваивания

Perl унаследовал такие операторы языка Си, как += , *= и т.п. Raku обобщает их до метаоператора. Для любого бинарного оператора op мы можем написать:

$x op= $y;  # или $x [op]= $y

Что значит:

$x = $x op $y;

Причем, это работает и для операторов, определённых пользователем.

Гипероператоры

Они похожи на оператор map в Perl. Заставляют операторы работать со всеми значениями массива. Могут применяться как к бинарным, так и к унарным операторам.

Например, следующий код создаст массив, содержащий все элементы массива @a , увеличенные на единицу:

my @aPlusOne = @a »+» 1;    # или @a >>+>> 1

Направление угловых скобок влияет на поведение при передаче в качестве параметров массивов разной длины. Эти «стрелки» показывают, откуда берётся длина результата операции.

Пример использования гипероператора с унарным оператором:

my @a = 1, 2, -3;
my @b = -<<@a;      # [-1 -2 3]

Гипероператоры работают не только для плоских, но и для вложенных массивов.

Метаоператор редукции

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

say "Сумма целых чисел от 0 до 99 равна: ", [+] ^100;

Кросс-оператор

Ведёт себя одновременно и как оператор, и как метаоператор.

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

1..3 X <a b c> X <d e f>;
# ((1 a d) (1 a e) (1 a f) 
#  (1 b d) (1 b e) (1 b f)
#  (1 c d) (1 c e) (1 c f)
#  (2 a d) (2 a e) (2 a f)
#  (2 b d) (2 b e) (2 b f)
#  (2 c d) (2 c e) (2 c f)
#  (3 a d) (3 a e) (3 a f)
#  (3 b d) (3 b e) (3 b f)
#  (3 c d) (3 c e) (3 c f))

Метаоператор сворачивает внутренние списки с помощью оператора-параметра:

1..3 X~ <a b c> X~ <d e f>;
# (1ad 1ae 1af 1bd 1be 1bf 1cd 1ce 1cf
#  2ad 2ae 2af 2bd 2be 2bf 2cd 2ce 2cf
#  3ad 3ae 3af 3bd 3be 3bf 3cd 3ce 3cf)

Зип-оператор

От англ. zipper застёжка-молния .

Аналогично кросс-оператору, совмещает элементы списков, но возвращает последовательность, содержащую сначала первые элементы каждого списка, затем вторые элементы каждого списка и т.д.

<a b c> Z <1 2 3 4>;
# ((a 1) (b 2) (c 3))

100, 200 Z+ 42, 23;
# (142 223)

Обратные операторы

Метаоператор R ( англ. reversed ) позволяет менять местами аргументы исходного оператора.

say "Один делить на три равно ", 3 R/ 1;

Вложенность метаоператоров

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

my @a = 1, 2, 3;
my @b = 5, 6, 7;

@a >>>>> @b;        # Ошибка разбора.
@a >>[>]>> @b;      # [False False False]
# Здесь гипероператор >> >> применяется к оператору сравнения.

# Кросс-метаоператор применяется
# к метаоператору присваивания, параметризованному
# оператором сложения:
@a X[+=] @b;        # (6 12 19 7 13 20 8 14 21)

# Из-за кросс-метаоператора, присваивание делалось
# для каждого элемента массива @a с каждым элементом массива @b,
# что эквивалентно прибавлению к каждому элементу массива @a
# суммы элементов массива @b:
say [+] @b;         # 18
say @a;             # [19 20 21]

Конкурентность и параллелизм

Подобно другим современным языкам, Raku спроектирован для поддержки параллелизма и асинхронного программирования.

Raku предоставляет простой модульный высокоуровневый API для написания конкурентного кода, независящий от способов реализации этого API виртуальной машиной. Кроме того, некоторые функции языка могут неявно работать асинхронно. Чтобы обеспечить управляемость и совместимость между этими функциями, пользовательскому коду следует избегать, насколько это возможно, использования низкоуровневых интерфейсов ( потоков , планировщиков, блокировок ).

Центральным высокоуровневым механизмом являются промисы ( англ. Promise — обещание), представляющие собой результаты вычислений, полученные до их фактического завершения. Их можно давать, выполнять и нарушать. Таким образом, они обладают тремя возможными состояниями. Сила этого механизма заключается в возможности их комбинировать и соединять в цепочки:

my $p1 = Promise.new();
my $p2 = $p1.then({ say "Результат второго промиса."});

Здесь then обеспечивает выполнение $p2 лишь после выполнения $p1 .

Есть также англ. Supplies («запасы») и англ. Suppliers («поставщики») — механизм создания асинхронных потоков данных с возможностью обработки каждого сообщения сразу несколькими получателями, подобно тому, как работают обработчики событий в других языках программирования. Этот механизм можно использовать для событийно-ориентированного программирования .

Наконец, каналы ( англ. Channels ) — это потокобезопасные FIFO - очереди , подобные именованным конвейерам в операционных системах, но функционирующие в рамках текущего процесса. Ключевое отличие от Supply в том, что чтение из канала является удалением из очереди, т.е. одно значение может быть прочитано лишь единожды.

Примеры

Hello world

Программа «Здравствуй, мир!» часто используется для демонстрации базового синтаксиса языка. На языке Raku она выглядит так:

say 'Hello, world';

Хотя, конечно, есть больше одного способа выразить это.

Факториал

Вычисление факториала , определённое несколькими способами:

# С использованием рекурсии с конструкцией «if-else».
sub fact( UInt $n --> UInt ) {
    if $n == 0 { 1 }
    else       { $n * fact($n-1) }
}

# С использованием рекурсии с «if»
# в качестве модификатора выражения.
sub fact( UInt $n --> UInt ) {
    return 1 if $n == 0;
    return $n * fact($n-1);
}

# С использованием рекурсии с конструкцией «when».
sub fact( UInt $n --> UInt ) {
    when $n == 0 { 1 }
    default      { $n * fact($n-1) }
}

# С использованием тернарного оператора.
sub fact( UInt $n --> UInt ) {
    $n == 0 ?? 1 !! $n * fact($n-1)
}

# С использованием множественной диспетчеризации.
multi fact(0) { 1 }
multi fact( UInt $n --> UInt ) {
    $n * fact($n - 1)
}

# С использованием метаоператора редукции.
sub fact( UInt $n --> UInt ) {
    [*] 1..$n
}

# Определение оператора факториала,
# реализованного через метаоператор редукции.
sub postfix:<!>( UInt $n --> UInt ) { [*] 1..$n }

# С использованием ключевого слова «state» для мемоизации.
sub fact( UInt $n --> UInt ) {
    state %known = 0 => 1;
    return %known{$n} if %known{$n}:exists;
    %known{$n} = $n * fact($n-1);
    return %known{$n};
}

QuickSort

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

# Отсортированный пустой список — это пустой список.
multi quicksort([]) { () }

# Иначе, берём первый элемент в качестве опорного...
multi quicksort([$pivot, *@rest]) {
    # Делим элементы на список тех,
    # которые меньше опорного, и те,
    # которые больше опорного.
    my @before = @rest.grep(* before $pivot);
    my @after  = @rest.grep(* after $pivot);

    # Сортируем эти подсписки и объединяем результат.
    flat (quicksort(@before), $pivot, quicksort(@after))
}
  1. Если компилятор не сделает что-нибудь загадочное за кулисами, максимальная глубина рекурсии здесь — длина списка, что делает эту реализацию непригодной для больших данных. Глубина рекурсии может быть сокращена до log2(длина_списка) , если использовать рекурсию только с небольшими подсписками before и after , и циклы в других случаях. Также, в этой реализации дублирующиеся значения исходного списка появятся в выводе лишь единожды, т.к. оба сравнения в параметрах метода grep строгие.

Ханойская башня

Эта головоломка часто используется для знакомства с рекурсией в информатике . Данная реализация использует мультиметоды с литералом 0 как часть сигнатуры .

multi sub hanoi(0, $, $, $) { }                         # Нет дисков. Нечего перекладывать.
multi sub hanoi($n, $a = 'A', $b = 'B', $c = 'C') {     # $n дисков и три стержня: A, B, C.
    hanoi $n - 1, $a, $c, $b;                           # Переместить ($n - 1) дисков с A на B
    say "Переместить диск $n с $a на $c.";              # Переместить последний диск с A на C.
    hanoi $n - 1, $b, $a, $c;                           # Переместить ($n - 1) дисков с B на C.
}

hanoi(5);   # Решение для пяти дисков.

См. также

Примечания

  1. (англ.) . — «楽土». Дата обращения: 26 июля 2022. 28 июля 2022 года.
  2. (яп.) . goo国語辞書 . — «心配や苦労がなく楽しい生活ができる土地。». Дата обращения: 27 августа 2021. 27 августа 2021 года.
  3. (англ.) . Edument . — «It means “comfort” or “ease” in Japanese, which nicely reflects the goals of the language to be a comfortable programming experience - as mentioned earlier, often at the expense of those doing the language implementation! The most popular compiler for the language is named “Rakudo”, which approximately means “way of the camel” (the camel being a symbol commonly associated with Perl) and also “paradise”. Thus, we can see it as a way to “do” the Raku language.» Дата обращения: 27 августа 2021. 27 августа 2021 года.
  4. (англ.) . JapanDict: Japanese Dictionary . — «Buddhism: sukha (happiness)». Дата обращения: 30 августа 2021. 30 августа 2021 года.
  5. (англ.) . — «Perl 6 will provide a "Perl 5 compatibility mode", allowing the compiler to directly execute any code that it recognizes as being written in Perl 5. [...] In Q2 2010 Patrick Michaud will release a useful and usable (but not feature complete) Perl 6 compiler...» Дата обращения: 3 сентября 2021. 3 сентября 2021 года.
  6. . Дата обращения: 18 октября 2019. 15 октября 2019 года.
  7. (англ.) . Perl 6 Archive (13 июля 2003). — «Damian spoke about Perl6::Rules, his implementation of Perl 6's rules system in pure Perl 5. [...] he told us [...] that the module would be completed and released to CPAN as time/money allowed and would be out by Christmas. He didn't say which Christmas.» Дата обращения: 27 августа 2021. 27 августа 2021 года.
  8. (англ.) . Perl Beginners' Site . — «<anonuser> You know for when they finally decide to release that programatic abortion they call perl 6 <rindolf> anonuser: on Christmas. <rindolf> anonuser: don't know which one.» 8 апреля 2012 года.
  9. . Дата обращения: 27 декабря 2015. 8 марта 2016 года.
  10. . Дата обращения: 15 июля 2021. 15 июля 2021 года.
  11. от 27 декабря 2015 на Wayback Machine .
  12. Federico Biancuzzi. Masterminds of Programming: Conversations with the Creators of Major Programming Languages / Federico Biancuzzi, Shane Warden. — 2009. — ISBN 978-0596515171 .
  13. Kline, Joe. (21 августа 2000). Дата обращения: 26 июля 2021. 4 июня 2009 года.
  14. Wall, Larry. . O'Reilly Network (23 октября 2000). Дата обращения: 26 июля 2021. 6 июня 2010 года.
  15. The Perl Foundation. . Дата обращения: 26 июля 2021. 26 июля 2021 года.
  16. Wall, Larry. (2 апреля 2001). Дата обращения: 26 июля 2021. 26 июля 2021 года.
  17. . Дата обращения: 26 июля 2021. 26 июля 2021 года.
  18. Larry Wall and the Perl 6 designers. . Дата обращения: 26 июля 2021. 26 июля 2021 года.
  19. The Perl Foundation. . Дата обращения: 26 июля 2021. 26 июля 2021 года.
  20. . Дата обращения: 14 августа 2021. 14 августа 2021 года.
  21. (англ.) . SEI CERT Perl Coding Standard . Carnegie Mellon University (16 ноября 2017). Дата обращения: 14 августа 2021. 14 августа 2021 года.
  22. Wall, Larry. (англ.) . Perl 6 Archive (2 октября 2001). Дата обращения: 29 августа 2021. 29 августа 2021 года.
  23. Wall, Larry. (англ.) . Perl 6 Archive (18 января 2002). Дата обращения: 29 августа 2021. 29 августа 2021 года.
  24. Wall, Larry. (англ.) . Perl 6 Archive (13 апреля 2004). Дата обращения: 29 августа 2021. 29 августа 2021 года.
  25. Simon Proctor (‎Scimon‎). (англ.) . Raku Advent Calendar (19 декабря 2019). Дата обращения: 29 августа 2021. 29 августа 2021 года.
  26. (англ.) . Perl.com (3 марта 2005). — Интервью с Autrijus Tang (Одри Тан). — «chromatic: Have you started giving Haskell tutorials? I know Larry and Patrick have started to pick up some of it. I’m pretty sure Luke and Damian have already explored it (or something from the same family tree). Autrijus: I think I’ve read a paper from Damian that says he taught Haskell in monash. It’s before the monadic revolution though. chromatic: If not Haskell, certainly something from the ML family. Autrijus: Right. So, I’ve been pointing people to YAHT and #Haskell. chromatic: It sounds like you’re attracting people from both sides of the fence then. Autrijus: It indeed is. I get svn/svk patches and darcs patches.» Дата обращения: 29 августа 2021. 29 августа 2021 года.
  27. (англ.) . Дата обращения: 14 августа 2021. 14 мая 2021 года.
  28. (15 января 2016). Дата обращения: 10 ноября 2017. Архивировано из 8 апреля 2016 года. (см. код страницы)
  29. (24 марта 2009). Дата обращения: 10 ноября 2017.
  30. от 12 августа 2021 на Wayback Machine : «Rakudo is currently the most actively developed and mature implementation of Raku».
  31. Wall, Larry. (10 августа 2004). Дата обращения: 15 августа 2021. 15 августа 2021 года.
  32. от 15 июля 2021 на Wayback Machine — обсуждение возможности распространения скомпилированного байт-кода.
  33. . Дата обращения: 15 июля 2021. 15 июля 2021 года.
  34. Worthington, Jonathan . 6guts . Дата обращения: 24 июля 2013. 9 июля 2013 года.
  35. . MoarVM team. Дата обращения: 8 июля 2017. 6 июня 2017 года.
  36. от 15 июля 2021 на Wayback Machine : «this is the last release of Rakudo that supports Parrot as a backend for the foreseeable future».
  37. от 16 июля 2021 на Wayback Machine : «We know what we need now» (шестой слайд)
  38. от 16 июля 2021 на Wayback Machine — страница выступления на сайте конференции с видео
  39. Pugs — Perl 6 user's golfing system.
  40. . 7 февраля 2019 года.
  41. (англ.) (22 августа 2006). — «Well, in short, we have divided the .t files in the Pugs test suite into pieces and inserted every resulting snippet after the corresponding paragraph of the Synopses.» Дата обращения: 28 августа 2021. 28 августа 2021 года.
  42. agentz. (англ.) . GitHub (16 августа 2006). Дата обращения: 28 августа 2021. 28 августа 2021 года.
  43. (англ.) . GitHub . Дата обращения: 28 августа 2021. 28 августа 2021 года.
  44. (англ.) . GitHub . — «4,590 commit results in Raku/roast». Дата обращения: 31 августа 2021. 31 августа 2021 года.
  45. (англ.) . Andrew Shitov (5 мая 2015). — «In August 2006, Yichun Zhang improved the continuous integration system, displaying tests inline with the spec, as detailed in this writeup. This makes the tests part of the spec, not particular to Pugs. In January 2008, Larry implemented a fudge program that adapts the test suite to work on new implementations such as SMOP and Rakudo. In February 2015, the community declared the tests at perl6/roast as the actual specification...» Дата обращения: 28 августа 2021. 28 августа 2021 года.
  46. Wall, Larry. (20 мая 2009). Дата обращения: 15 августа 2021. 8 мая 2021 года.
  47. . Дата обращения: 15 августа 2021. 23 апреля 2022 года.
  48. Wall, Larry. (21 марта 2003). Дата обращения: 15 августа 2021. 15 августа 2021 года.
  49. Wall, Larry. (20 мая 2009). Дата обращения: 15 августа 2021. 15 августа 2021 года.
  50. . Записки программиста (7 апреля 2011). Дата обращения: 21 августа 2021. 21 августа 2021 года.
  51. Wall, Larry. (18 августа 2006). Дата обращения: 21 августа 2021. 21 августа 2021 года.
  52. (англ.) . Raku Documentation . Дата обращения: 21 августа 2021. 21 августа 2021 года.
  53. . Хабр (20 апреля 2011). Дата обращения: 22 августа 2021. 22 августа 2021 года.
  54. (англ.) . Raku Documentation . Дата обращения: 21 августа 2021. 21 августа 2021 года.
  55. The Software Composition Group. . Дата обращения: 22 сентября 2006. 11 августа 2006 года.
  56. Jonathan Worthington. . Дата обращения: 21 августа 2021. 21 августа 2021 года.
  57. . Введение в Raku . Дата обращения: 15 июля 2021. 15 июля 2021 года.
  58. chromatic. . Дата обращения: 21 августа 2021. 16 июля 2021 года.
  59. . docs.raku.org . Дата обращения: 22 августа 2021. 21 августа 2021 года.
  60. Parlante, Nick. . Дата обращения: 21 августа 2021. 21 апреля 2012 года.
  61. Christiansen, Tom. . — «Perl's regexps "aren't" -- that is, they aren't "regular" because backreferences per sed and grep are also supported, which renders the language no longer strictly regular». Дата обращения: 25 марта 2010. 31 марта 2010 года.
  62. (англ.) . Raku Documentation . Дата обращения: 22 августа 2021. 22 августа 2021 года.
  63. Wall, Larry. (20 мая 2009). Дата обращения: 22 августа 2021. 22 августа 2021 года.
  64. Wall, Larry. (4 июня 2002). Дата обращения: 22 августа 2021. 22 августа 2021 года.
  65. Wall, Larry. (13 сентября 2004). Дата обращения: 22 августа 2021. 22 августа 2021 года.
  66. (англ.) . Raku Documentation . — «The gather/take combination can generate values lazily, depending on context. If you want to force lazy evaluation use the lazy subroutine or method. Binding to a scalar or sigilless container will also force laziness.» Дата обращения: 22 августа 2021. 21 августа 2021 года.
  67. . Введение в Raku . Дата обращения: 15 июля 2021. 15 июля 2021 года.
  68. (англ.) . Raku Documentation . Дата обращения: 23 августа 2021. 23 августа 2021 года.
  69. Lamkins, David B. . — bookfix.com, 2004-12-08. . Дата обращения: 23 августа 2021. Архивировано из 12 сентября 2006 года.
  70. (англ.) . Raku Documentation . Дата обращения: 23 августа 2021. 23 августа 2021 года.
  71. (англ.) . Дата обращения: 23 августа 2021. 14 августа 2021 года.
  72. (англ.) . Vue.js . Дата обращения: 23 августа 2021. 12 августа 2021 года.
  73. Ivan Grishaev. (англ.) (6 мая 2021). Дата обращения: 23 августа 2021. 23 августа 2021 года.
  74. (англ.) . Дата обращения: 24 августа 2021. 3 августа 2021 года.
  75. Андрей Шитов. . Pragmatic Perl (27 мая 2015). Дата обращения: 23 августа 2021. 23 августа 2021 года.
  76. (англ.) . Raku Documentation . Дата обращения: 24 августа 2021. 3 августа 2021 года.
  77. (англ.) . Raku Documentation . Дата обращения: 24 августа 2021. 3 августа 2021 года.
  78. Kurt Nørmark. (англ.) . Department of Computer Science, Aalborg University, Denmark . — «The zipping function is named after a zipper, as known from pants and shirts.» Дата обращения: 24 августа 2021. 24 августа 2021 года.
  79. (англ.) . Дата обращения: 24 августа 2021. 3 августа 2021 года.
  80. (англ.) . Raku Documentation . Дата обращения: 24 августа 2021. 3 августа 2021 года.
  81. (англ.) . Raku Documentation . Дата обращения: 25 августа 2021. 21 августа 2021 года.
  82. . Современный учебник JavaScript (15 июля 2020). Дата обращения: 27 августа 2021. 27 августа 2021 года.
  83. . MDN . — «исполнение промиса протоколируется при помощи продолжения p1.then. Это показывает как синхронная часть метода отвязана от асинхронного завершения промиса». Дата обращения: 27 августа 2021. 26 августа 2021 года.
  84. (англ.) . Stack Overflow . Дата обращения: 1 сентября 2021. 1 сентября 2021 года.
  85. (англ.) . Perl.com (31 августа 2010). — Интервью с разработчиком Rakudo по имени Carl Mäsak. — «I’ve also gained a new respect for what a “holistic” process the design of a language such as Perl 6 can be sometimes. Whether some feature turns out to be a good idea is determined by dozens of minute interactions in the spec, not all of them “local”, and some of them outright emergent.» Дата обращения: 29 августа 2021. 29 августа 2021 года.
  86. Larry Wall. (англ.) . Perl.com (9 марта 1999). — Текст выступления Ларри Уолла на Linux World третьего марта 1999 года. Дата обращения: 30 августа 2021. 11 августа 2021 года.

Литература

Книги, опубликованные до релиза языка (до версии 6.c)

  • Allison Randal, Dan Sugalski, Leopold Tötsch. . — O'Reilly Media , 2004. — 279 p. — ISBN 059600737X , 9780596007379.
  • Scott Walters. . — Apress , 2004. — 424 p. — ISBN 1590593952 , 9781590593950.
  • Мориц Ленц (Moritz Lenz, Германия), перевод Анатолия Шарифулина (уроки 1—6) и Андрея Шитова (7—20). // Сетевые решения. — Минск: ИД "Нестор", 2008. — № 9 .

Ссылки

Источник —

Same as Raku