【问题标题】:About Laziness [ RAKU ]关于懒惰 [ RAKU ]
【发布时间】:2020-05-04 10:36:08
【问题描述】:

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

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

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

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

【问题讨论】:

  • “在 Raku 文档中指出,gather-take 构造正在被延迟评估。”他们可以。但不一定。请提供您正在阅读的特定文档的链接。

标签: arrays lazy-evaluation raku lazy-sequences rakudo


【解决方案1】:

在 Raku 文档中指出,gather-take 构造正在被惰性求值。

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

在一个关键的转折中,如果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-lazygather 构造上被调用时,它返回 False

采取 #5:您的示例中发生了什么

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

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


前缀lazy 创建一个新的Seq,它懒洋洋地从右边的表达式中提取。如果在其上调用.is-lazy,它也会返回True

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

如果为@ sigil 的变量分配了一个值,该值返回True 以调用.is-lazy,则分配和变量都是惰性的。所以代码@f1 = lazy gather ... 工作正常。


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

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

因此,无论有没有lazy,分配它也可以正常工作。


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


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

@ sigil 变量一样,在$ sigil 变量或无符号标识符上调用.is-lazy 将返回TrueFalse,与分配/绑定的Seq 一致.

但是,不管.is-lazy 是返回True 还是FalseSeq 仍然会惰性地进行迭代

【讨论】:

  • FWIW,我发现say .is-lazy with 1..Inf 阅读起来更清晰,因为它不会让您认为它可能会遍历该范围,
  • @ElizabethMattijsen 我以一种我认为合理的方式修复了它(say (1..Inf) .is-lazy;,所以没有for)。但随后您的评论在 编辑之后得到了支持。唔。因此,现在它已修复为与您所写的完全相同。语言和清晰的编码是如此微妙的事情! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2012-06-02
  • 2015-09-06
  • 1970-01-01
相关资源
最近更新 更多