Как стать автором
Обновить

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

Время на прочтение3 мин
Количество просмотров7.6K
Автор оригинала: colomon
В 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


Кроме этого, оператор последовательности не ограничен работой исключительно с числами. Задавая собственную функцию для подсчёта следующего элемента списка, вы можете составить его из каких угодно элементов.
Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 27: ↑27 и ↓0+27
Комментарии7

Публикации

Истории

Ближайшие события