День 6: Входя в Гиперпространство
Вольный перевод шестой статьи цикла Perl 6 Advent Calendar на русский язык.
Вчера pmichaud предствавил гипероператоры Perl 6 (рус.). Я хотел бы продолжить обзор этих мощных метаоператоров.
Во-первых, я буду использовать вспомогательную функцию lsay для упрощения и красивого вывода списков.
sub lsay(@a) { @a.perl.say }
Теперь мы можем начать рассматривать примеры гипероператоров. В этой заметке я буду использовать >> и << вместо » и «, в основном потому, что они легче для моих глаз. (Я боюсь, что потребуется взять очки.) » и «, как правило, считаются истинной записью оператора, но ASCII-версия так же будет работать.
Для начала основы: складываем два списка одинаковой длины:
> lsay (1, 2, 3, 4) <<+>> (3, 1, 3, 1) [4, 3, 6, 5] > lsay (1, 2, 3, 4) >>+<< (3, 1, 3, 1) [4, 3, 6, 5]
При одинаковой длине массивов нет никакой разницы между этими формами. Но если длина различна:
> lsay (1, 2, 3, 4) <<+>> (3, 1) [4, 3, 4, 5] > lsay (1, 2, 3, 4) >>+<< (3, 1) Non-dwimmy hyperoperator cannot be used on arrays of different sizes or dimensions.
Как правило, список, на который указывает гипероператор "острым" концом, может быть расширен если он короче чем другой; он расширяется повторением последнего элемента этого списка. В тоже время список, на который указывает "тупой" конец гипероператора, не может быть расширен. Все комбинации разрешены, поэтому вы можете указать на то, что расширена может быть только левая сторона (<<+<<), только правая (>>+>>), обе стороны могут быть расширены (<<+>>), или ни одна из сторон не может быть расширена (>>+<<). Одиночные скаляры так же расширяемы:
> lsay (1, 2, 3, 4) >>+>> 2 [3, 4, 5, 6] > lsay 3 <<+<< (1, 2, 3, 4) [4, 5, 6, 7]
В основном, гипероператоры используются с инфиксными операторам. Теоретически, вы так же можете использовать их с префиксными или постфиксными операторами:
> lsay ~<<(1, 2, 3, 4) ["1", "2", "3", "4"] > lsay (1, 2, 3, 4)>>++ [2, 3, 4, 5]
На практике такое использование не было осуществлено в Rakudo, за исключением одного особого случая:
> lsay (0, pi/4, pi/2, pi, 2*pi)>>.sin [0, 0.707106781186547, 1, 1.22464679914735e-16, -2.44929359829471e-16] > lsay (-1, 0, 3, 42)>>.Str ["-1", "0", "3", "42"]
То есть >>. вызывает метод Str на каждом элементе списка.
Насколько бы вам не хотелось написать @array>>.say, не делайте этого. Это может работать в текущей версии Rakudo, но при использовании гипероператоров вы обещаете что операция параллелизуема, и порядок операций на списке(-ах) не фиксирован. Надеюсь, что в будущих версиях Perl 6 эти операции будут выполняться параллельно.
Другие примечания: Гипероператоры работают не только со встроенными операторами. Они будут работать с любым новым оператором который вы определите. (В основном, сейчас это уже работает в Rakudo.) Гипероператоры будут работать с in-place операторами, напрмиер @a >>/=>> 2 разделит весь массив на 2. (Это не работает в текущей версии Rakudo.) Они будут работать с многомерными списками, с деревьями и с хэшами; смотрите S03 Hyper operators. (Насколько я знаю, они еще не работают в Rakudo.)
Я больше не знаю примеров использования, но область применения гипероператоров достаточно широка. Например класс Vector написанный LastOfTheCarelessMen довольно неплох — это реализация N-мерного вектора без единой явной петли.