7

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

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

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

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

4

1 回答 1

10

在 Raku 文档中指出,收集-获取构造正在被延迟评估。

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

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

采取#1:一种gather行为懒惰

gather在需要时评估其序列中的下一个元素。这是惰性评估的经典定义,如 Wikipedia 所述

惰性求值...延迟表达式的求值,直到需要它的值

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

一些消耗值序列的结构总是懒惰地消耗它们。如果他们正在消费的序列是 a gather,他们就会懒惰地要求它的值。在这种情况下,gather有义务评估它的序列直到它到达 a take,然后让步直到需要下一个值。

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

一些消耗值序列的构造总是急切地消耗它们。如果他们正在消费的序列是 a 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正在分配一个序列,表明它不是懒惰的。即使它包含无限循环也是如此。@印记的变量将其作为急切分配序列的提示 - 并且代码挂起。


前缀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.


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


您没有问过这个问题,但另一种情况是将 a 分配或绑定Seq到一个有印记的$变量或一个无印记的标识符。

@sigil'd 变量一样,调用.is-lazysigil'd$变量或 sigil free 标识符将返回TrueFalse与分配/绑定一致Seq

但是,不管that是否.is-lazy返回True,仍然会被lazily迭代。FalseSeq

于 2020-01-17T15:52:53.777 回答