9. Gather и take в Perl 6

Два ключевых слова — gather и take — появились чуть ли не в самой ранней версии Perl 6. Давайте посмотрим, как они работают сегодня.

Пару дней назад мы видели, как gather и take коллекционировали промисы от параллельных потоков. Вот более простой пример:

my @data = gather {
    take 'a';
    take 'b';
    take 'c';
};
say @data; # [a b c]

Этот пример довольно прозрачен: три вызова take собирают данные в последовательность, которую и возвращает gather.

Обратите внимание, что возвращается именно последовательность (sequence), которая представлена типом Seq. Тип данных всегда можно посмотреть, вызвав на объекте метод WHAT:

(gather {
    take 'a';
    take 'b';
    take 'c';
}).WHAT.say; # (Seq)

Действие gather распространяется и на другие take, которые, например, происходят при вызове функций внутри gather. Следующий пример дает об этом представление:

my @a = gather {
    take 'a';
    f('b');
}

sub f($x) {
    take $x;
}

say @a; # [a b]

lazy gather

Наконец, модификация для ленивых вычислений — блок lazy gather. Немного модифицируем предыдущий пример, чтобы функция сообщала о своем вызове:

my @data = gather {
    take f('a');
    take f('b');
    take f('c');
}

sub f($x) {
    say "Taking $x";
    return $x;
}

Эта программа сразу печатает три строки:

Taking a
Taking b
Taking c

Если же перед gather поставить lazy, программа завершится, ничего не напечатав.

Однако, код после take будет выполняться по мере того, как мы начнем читать данные из массива:

my @data = lazy gather {
    take f('a');
    take f('b');
    take f('c');
}

sub f($x) {
    say "Taking $x";
    return $x;
}

say @data[0];

Программа сначала сообщит о «взятии» первого значения, а потом напечатает его:

Taking a
a

Если же попытаться сразу вывести, например, третий элемент (say @data[2]), то сработают все три take:

Taking a
Taking b
Taking c
c

3 thoughts on “9. Gather и take в Perl 6”

  1. А есть ли возможность запустить gather/take больше чем в «один поток», т.е. чтобы в одном месте программы работал gather1/take1, а в другом gather2/take2?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *