关于懒惰 [ RAKU ]

About Laziness [ RAKU ]

在 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)如果我们去掉 "lazy" 定义,那么生成的序列(使用 gather-take)永远是 运行(不是懒)。

在第二种情况下(将 Seq 分配给@f2)@f2 变得懒惰。

为什么我们的行为会有所不同?尽管我们尝试做同样的事情:以惰性方式将 Seq 分配给数组

有人可以澄清一下吗???

In Raku documentation it is stated that gather-take constructs are being lazy evaluated.

他们可以。但不一定。无论哪种方式,他们都非常乐意工作。

在一个关键的转折中,如果 gather 询问 是否懒惰,它 return 就会 False。这就是导致您看到的行为的原因。

采取 #1:一种方式 gather 表现得 懒惰

gather 在需要时计算其序列中的下一个元素。这是 the classic definition of lazy evaluation, as described by Wikipedia:

lazy evaluation ... delays the evaluation of an expression until its value is needed

采取 #2:第二种方式 gather 表现得 懒惰

一些使用值序列的构造总是延迟使用它们。如果他们消费的序列是 gather,他们会懒惰地要求它的值。在这种情况下 gather 有义务,评估其序列直到它达到 take,然后 yielding 直到需要下一个值。

采取 #3:一种方式 gather 表现得 急切

一些消耗值序列的构造总是急切地消耗它们。如果他们正在消费的序列是 gather,他们会急切地要求它的值。在这种情况下,gather 有义务,任何懒惰都是没有意义的。

采取#4:第二种方式gather表现急切

一些使用值序列的构造根据序列对 .is-lazy 呼唤它;如果它 returns True,那么它的值是惰性要求的,否则它们是急切要求的。

这里出现了一个关键的转折:当在 gather 构造上调用 .is-lazy 时,它 returns False.

练习 #5:您的示例中发生了什么

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

在您的 @f1 = gather ... 案例中,@f1 被分配了一个表明它 不是 惰性的序列。即使它包含无限循环也是如此。 @ sigil'd 变量将其视为 急切地 分配序列的提示 - 代码挂起。


前缀 lazy 创建了一个新的 Seq,它懒惰地从其右侧的表达式中提取。它还 returns True 如果 .is-lazy 被调用:

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

如果@ sigil'd 变量被赋值为returns True 用于调用.is-lazy,赋值和变量是懒惰的。所以代码 @f1 = lazy gather ... 工作正常。


最后,序列 (1...Inf) 知道 它是惰性的,并告诉世界它是惰性的,不需要前缀 lazy:

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

因此无论有无 lazy.

,分配都可以正常工作

总而言之,如果分配给它的 Seq 表示它是惰性的,则 @ 标记的变量会惰性地获得元素,否则会急切地获得元素。


你没有问这个,但另一种情况是将 Seq 分配或绑定到 $ 印记变量,或印记自由标识符。

@ 印记变量一样,在 $ 印记变量或印记自由标识符上调用 .is-lazy 将 return TrueFalse 符合 assigned/bound Seq.

但是,不管.is-lazyreturn还是True还是FalseSeq 仍然会 lazily.

迭代