gpt4 book ai didi

raku - 如何使用定义的生成器构建惰性列表,是否有 "takeWhile"替代方案?

转载 作者:行者123 更新时间:2023-12-04 22:19:07 27 4
gpt4 key购买 nike

我正在阅读 perl6intro on lazy lists,这让我对某些事情感到困惑。

拿这个例子:

sub foo($x) {
$x**2
}

my $alist = (1,2, &foo ... ^ * > 100);

会给我 (1 2 4 16 256) ,它会平方相同的数字,直到它超过 100。我希望这给我 (1 4 9 16 25 .. ) ,所以不是平方相同的数字,而是将 x 推进一个数字 1(或另一个给定的“步骤”), foo x ,等等。

在这种特定情况下是否有可能实现这一目标?

我对惰性列表的另一个问题如下:
在 Haskell 中,有一个 takeWhile 函数,在 Perl6 中是否存在类似的东西?

最佳答案

以下是编写 Perl 6 等效于 Haskell 的 takewhile 的方法。

sub take-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;

my \generator = gather loop {
my \value = iterator.pull-one;
last if value =:= IterationEnd or !condition(value);
take value;
}

# should propagate the laziness of the sequence
sequence.is-lazy
?? generator.lazy
!! generator
}

我可能还应该展示 dropwhile 的实现。

sub drop-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;

GATHER: my \generator = gather {

# drop initial values
loop {
my \value = iterator.pull-one;

# if the iterator is out of values, stop everything
last GATHER if value =:= IterationEnd;

unless condition(value) {
# need to take this so it doesn't get lost
take value;

# continue onto next loop
last;
}
}

# take everything else
loop {
my \value = iterator.pull-one;
last if value =:= IterationEnd;
take value
}
}

sequence.is-lazy
?? generator.lazy
!! generator
}

这些只是刚开始工作的例子。

可以说这些值得作为方法添加到列表/可迭代对象中。

您可以(但可能不应该)使用序列生成器语法实现这些。

sub take-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
my \generator = { iterator.pull-one } …^ { !condition $_ }
sequence.is-lazy ?? generator.lazy !! generator
}

sub drop-while ( &condition, Iterable \sequence ){
my \end-condition = sequence.is-lazy ?? * !! { False };
my \iterator = sequence.iterator;

my $first;
loop {
$first := iterator.pull-one;
last if $first =:= IterationEnd;
last unless condition($first);
}

# I could have shoved the loop above into a do block
# and placed it where 「$first」 is below

$first, { iterator.pull-one } … end-condition
}

如果将它们添加到 Perl 6/Rakudo,它们很可能会使用 Iterator 类来实现。
(我可能会去添加它们。)

你所要求的直接实现是这样的:

do {
my $x = 0;
{ (++$x)² } …^ * > 100
}

这可以用状态变量来完成:

{ ( ++(state $x = 0) )² } …^ * > 100

并且在声明之外不使用的状态变量不需要名称。
(标量变量以未定义的 Any 开始,在数字上下文中变为 0)

{ (++( $ ))² } …^ * > 100
{ (++$)² } …^ * > 100

如果需要初始化匿名状态变量,可以使用定义或运算符 // 与相等的元运算符 = 结合使用。

{ (++( $ //= 5))² } …^ * > 100

在一些简单的情况下,您不必告诉序列生成器如何计算下一个值。
在这种情况下,结束条件也可以简化。

say 1,2,4 ...^ 100
# (1 2 4 8 16 32 64)

唯一可以安全地简化结束条件的时间是,如果 知道 它将停止在该值上。

say 1, { $_ * 2 } ... 64;
# (1 2 4 8 16 32 64)

say 1, { $_ * 2 } ... 3;
# (1 2 4 8 16 32 64 128 256 512 ...)

关于raku - 如何使用定义的生成器构建惰性列表,是否有 "takeWhile"替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41194693/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com