День 5: Метаоператоры
Перевод пятой статьи цикла Perl 6 Advent Calendar на русский язык.
В коробке четвертого дня мы видели интересную функцию для нахождения факториала:
sub fac(Int $n) {
[*] 1..$n
}
Итак, как же она работает? Открытие сегодняшней праздничной коробки даст нам ответы на некоторые вопросы!
Perl 6 имеет несколько различных “мета операторов”, которые изменяют существующие операторы для предоставления нам более мощного функционала.
Квадратные скобки являются “метаоператором сокращения”. Они позволяют встроить оператор, находящийся между скобок, в правую часть выражения. Оператор в таких скобках будет помещен между каждой парой элементов списка. Например выражение
[+] 1, $a, 5, $b
можно записать как
1 + $a + 5 + $b
Это дает нам удобный механизм “сумма всех элементов в списке”:
$sum = [+] @a; # сумма всех элементов массива @a
Большинство встроенных операторов (включая пользовательские) могут быть помещены в квадратные скобки чтобы сократить запись:
$prod = [*] @a; # умножение всех элементов @a $mean = ([+] @a) / @a; # рассчитать среднее значение @a $sorted = [<=] @a; # возвратит true если элементы в @a численно отсортированы $min = [min] @a, @b; # находит наименьший элемент в объединенных @a и @b
Теперь мы видим, что в функции поиска факториала выражение
[*] 1..$n
возвращает результат умножения всех чисел от 1 до $n.
Другим полезным метаоператором является “гипер-оператор”. Помещение »
и/или « (или ASCII эквивалент >> и <<) рядом с оператором превращает его в “гипер-оператор”, который работает с элементами списка. Например следующее поместит в @c результат попарного сложения элементов в @a и @b:
@c = @a »+« @b;
В Perl 5 мы бы написали примерно следующее:
for ($i=0; $i<@a; $i++) {
$c[$i] = $a[$i] + $b[$i];
}
что выглядит несколько длиннее.
Как и в случае с оператором сокращения, мы можем использовать этот оператор с рядом встроенных или пользовательских:
# увеличение всех элементов в @xyz на еденицу @xyz»++ # каждый элемент в @x будет минимальным из @a и @b @x = @a »min« @b;
Мы так же можем повернуть углы, чтобы скаляры работали как массивы:
# умножает каждый элемент @a на 3.5
@b = @a »*» 3.5;
# умножает каждый элемент @x на $m и прибавляет $b
@y = @x »*» $m »+» $b;
# обращает все элементы @x
@inv = 1 «/« @x;
# объединяет @last, @first и помещает в @full
@full = (@last »~» ', ') »~« @first;
Разумеется, операторы сокращения и гипер-операторы можно использовать одновременно:
# вычислить сумму квадратов элементов в @x $sumsq = [+] ( @x »**» 2);
Существует много других доступных метаоператоров, включая X (крест), R (обращение), S (последовательность). На самом деле “in-place” операторы, такие как +=, *=, ~=, являются лишь метаформой оператора равенства:
$a += 5; # так же как $a = $a + 5; $b //= 7; # так же как $b = $b // 7; $c min= $d; # так же как $c = $c min $d;