在 Raku 文档中指出,gather-take 构造正在被惰性评估。在下面的例子中,我很难对结构的懒惰得出结论:

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

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

为什么我们在行为上有差异?尽管我们尝试做同样的事情:以懒惰的方式将 Seq 分配给数组

有人能澄清一下吗???

最佳答案


他们可以。但不一定。他们非常乐意以任何一种方式工作。
关键的一点是,如果 gather 被询问它是否是惰性的,它会返回 False 。这就是您看到的行为的结果。
采取 #1:gather 表现懒惰的一种方式gather 在需要时评估其序列中的下一个元素。这是 the classic definition of lazy evaluation, as described by Wikipedia :

采取#2:gather 懒惰行为的第二种方式
一些消耗值序列的构造总是懒惰地消耗它们。如果他们使用的序列是 gather ,他们会懒惰地要求它的值。在这种情况下, gather 有义务,评估其序列直到达到 take ,然后 yielding 直到​​需要下一个值。
采取 #3:gather 表现得热切的一种方式
一些消耗值序列的构造总是急切地消耗它们。如果他们使用的序列是 gather ,他们会急切地要求它的值。在这种情况下 gather 有义务,并且其中的任何懒惰都没有实际意义。
采取 #4:gather 表现得热切的第二种方式
根据序列对 .is-lazy 调用的响应,一些消耗值序列的构造要么懒惰要么急切地要求它们;如果它返回 True ,那么它的值被懒惰地要求,否则他们急切地被要求。
这里有一个关键的转折:当在 .is-lazy 构造上调用 gather 时,它​​返回 False
采取#5:您的示例中发生了什么

say .is-lazy
for (gather { take 42 }),                 # False
    (gather { loop { take 42 } });        # False
在您的 @f1 = gather ... 案例中, @f1 被分配了一个序列,表示它不是懒惰的。即使它包含无限循环也是如此。 @ sigil'd 变量将其作为急切分配序列的提示 - 代码挂起。

前缀 lazy 创建了一个新的 Seq,它从其右侧的表达式中懒惰地绘制。如果 True 被调用,它也会返回 .is-lazy:
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

总之,如果分配给 @Seq 表示它是惰性的,则 Seq sigil'd 变量会懒惰地获取元素,否则会急切地获取元素。

您没有问过这个问题,但另一种情况是将 $ 分配或绑定(bind)到 @ sigil 变量或无 sigil 标识符。
.is-lazy sigil'd 变量一样,在 $ sigil'd 变量或 sigil free 标识符上调用 True 将根据分配/绑定(bind)的 False 返回 Seq.is-lazy
但是,无论 True 返回 False 还是 Seq , ojit_code 仍然会被懒惰地迭代。

10-05 20:29