О лени [РАКУ] - PullRequest
       62

О лени [РАКУ]

7 голосов
/ 17 января 2020

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

say 'Iterate to Infinity is : ', (1 ... Inf).WHAT;

say 'gather is : ', gather {
    take 0;
    my ($last, $this) = 0, 1;

    loop {
        take $this;
        ($last, $this) = $this, $last + $this;
    }
}.WHAT;

say '------------------------------------';

my @f1 = lazy gather {
    take 0;
    my ($last, $this) = 0, 1;

    loop {
        take $this;
        ($last, $this) = $this, $last + $this;
    }
}

say '@f1         : ', @f1.WHAT;
say '@f1 is lazy : ', @f1.is-lazy;

say '------------------------------------';

my @f2 = 1 ... Inf;

say '@f2         : ', @f2.WHAT;
say '@f2 is lazy : ', @f2.is-lazy;

В первом случае (присвоение Seq для @ f1), если мы уберем определение «ленивый», тогда сгенерированная последовательность (с использованием команды take-take) работает вечно (НЕ ленивый).

Во втором случае (присвоение Seq для @ f2) @ f2 становится ленивым.

Почему у нас есть различия в поведении? хотя мы пытаемся сделать то же самое: назначить Seq массиву ленивым способом

Может кто-нибудь прояснить вопрос ???

1 Ответ

8 голосов
/ 17 января 2020

Хотя gather / take спроектирован как полезная конструкция для отложенной обработки, он говорит всем, кто спрашивает, что он не является отложенным, независимо от того, содержит ли он бесконечное число. l oop:

say .is-lazy
for (gather { take 42 }),                 # False
    (gather { loop { take 42 } });        # False

Итак, в вашем @f1 = gather ... случае @f1 присваивается последовательность, которая говорит, что она не ленива, даже если она содержит бесконечное l oop. @ переменные sigil'd принимают это как сигнал для с нетерпением назначают последовательность - и код зависает.


Префикс lazy создаст новый Seq это будет лениво рисовать из выражения справа от него. Новый Seq, созданный lazy, сообщает миру, что it (новый Seq) ленив:

say .is-lazy
for (lazy gather { take 42 }),            # True
    (lazy gather { loop { take 42 } });   # True

Если переменная @ sigil'd присваивается значение, которое возвращает True для вызова .is-lazy, тогда присваивание и переменная являются ленивыми. Так что код @f1 = lazy gather ... работает отлично.


Наконец, последовательность (1...Inf) знает , что это лениво, и говорит миру, что это без префикса lazy:

say .is-lazy with (1 ... Inf)             # True

Таким образом, назначение, которое также работает нормально, с или без lazy.


Таким образом, переменная @ sigil'd получает элементы лениво, если назначено Seq ему сказано, что это лениво, и с нетерпением жду иного.


Вы не спрашивали об этом, но другой сценарий - это присвоение или привязка Seq к переменной $ sigil'd или идентификатор без сигилов.

Как и для переменной @ sigil'd, вызов .is-lazy для переменной $ sigil'd или идентификатор без сигилов вернет True или False в соответствии с назначенный / связанный Seq.

Но затем, независимо от того, от того, вернет ли .is-lazy True или False, Seq все равно будет повторяться лениво .

...