[Перевод] Последовательности в Perl 6 / Rakudo

В Perl 6 введён новый оператор … для задания последовательностей. Вот, как это работает: my @even-numbers:= 0, 2 … *; # арифметическая последовательность my @odd-numbers:= 1, 3 … *; my @powers-of-two:= 1, 2, 4 … *; # геометрическая последовательность Пример использования:

> my @powers-of-two:= 1, 2, 4 … *; 1; 1 > @powers-of-two[^10] 1 2 4 8 16 32 64 128 256 512 (При задании в REPL геометрической последовательности, которая бесконечна по определению, я поставил в конце строчки »1;». В результате REPL выводит единицу, и не уходит в бесконечный цикл.)Чтобы ограничить бесконечную «ленивую» последовательность, в примере я использовал запись [^10], что означает «первые десять элементов». При такой записи подсчитанные переменные запоминаются для дальнейшего использования.

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

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

> my @Fibonacci:= 0, 1, → $a, $b { $a + $b } … *; 1; 1 > @Fibonacci[^10] 0 1 1 2 3 5 8 13 21 34 Часть → $a, $b { $a + $b } — это стрелочный блок (лямбда-функция), принимающая два аргумента, и возвращающая их сумму. Оператор последовательности вычисляет, сколько аргументов принимает блок, и передаёт нужное количество с конца последовательности для генерации следующего числа.

Пока что у всех примеров в конце была указана звёздочка, означающая «что угодно». В этом случае у списка нет конца. Если вы поставите там число, оно станет окончанием списка.

> 1, 1.1 … 2 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 > 1, 1.1 … 2.01 … шестерёнки Rakudo вращаются, ибо этот список бесконечен … > (1, 1.1 … 2.01)[^14] 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.1 2.2 2.3 Первый список оканчивается естественным образом, но второй проходит мимо ограничителя. В результате мы получаем бесконечный список — поэтому я ограничил его 14-ю элементами, просто чтобы увидеть, что он выдаёт.

Программисты, знакомые с вычислениями с плавающей запятой, наверно ворчат, что нельзя предполагать, будто последовательное добавление 0.1 к числу обязательно приведёт к двойке. В Perl 6 используется Rat-математика, которая обеспечивает точность и работоспособность таких вычислений.

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

> 0, 1, → $a, $b { $a + $b } … → $a { $a > 10000 }; 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 Стрелочный блок → $a { $a > 10000 } создаёт проверку. Она принимает один аргумент и возвращает true, когда он становится больше 10000.

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

> 0, 1, → $a, $b { $a + $b } …^ → $a { $a > 10000 }; 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 Используя замыкания «чего угодно», эту запись можно переделать следующим образом:

> 0, 1, * + * …^ * > 10000; 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 Яснее такая запись, или сложнее — вам решать.

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

> my @Fibonacci:= 0, 1, * + * … *; 1; 1 > @Fibonacci …^ * > 10000 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 > @Fibonacci[30] 832040 Кроме этого, оператор последовательности не ограничен работой исключительно с числами. Задавая собственную функцию для подсчёта следующего элемента списка, вы можете составить его из каких угодно элементов.

© Habrahabr.ru