Курс языка программирования Raku / Функциональное, конкурентное, реактивное и веб-программирование / Функциональное программирование / Генераторы

Ленивый gather

Блок gather ленив: он не выполняется весь сразу. Он выдаёт значения лишь по мере того, как их вытягивают, а это значит, что gather может описывать бесконечную череду и всё равно оставаться полезным: вы просто перестаёте брать значения, когда их достаточно.

Загвоздка в том, что результат надо сохранить ленивым. Складывание его в обычный @array попыталось бы собрать сразу все значения, а для бесконечной череды это никогда не закончится. Вместо этого держите последовательность в скаляре (там она остаётся ленивой Seq) и вытягивайте из неё срез:

my $naturals = gather {
    my $n = 1;
    loop {
        take $n++;
    }
}

say $naturals[^5]; # (1 2 3 4 5)

Цикл loop не кончается никогда, но производится ровно пять значений, потому что именно столько мы и запросили через [^5]. Вытягивать с начала можно и методом .head:

say (gather { my $n = 1; loop { take $n++ } }).head(3); # (1 2 3)

Именно лень и позволяет gather безопасно моделировать бесконечные потоки: ничего не вычисляется, пока не понадобится, и вы берёте ровно столько, сколько хотите.

Навигация по курсу

Тест — gather и take   |   Соберите кубы


💪 Или перейдите сразу к упражнениям этого раздела.