在 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 仍然会被懒惰地迭代。