如何在 Raku 中无限期和懒惰地循环列表?
how to cycle through list indefinitely and lazily in Raku?
这主要是为了了解 Raku 有多棒。
问题
是否有内置方法可以获取一个列表并无限循环它,从而生成惰性列表
a, b, c, a, b, c, ...
出(a, b, c)
? documentation 列表中的任何内容似乎都无法解决问题。
可能的解决方案
我至少能想到几个。
更沉闷的脚踏实地的方法是 map @array[<variable> mod length-of-@array]
在惰性范围 0..Inf
上。在 perl6
REPL 中:
> my @ar=<a b c>
[a b c]
> (0..Inf).map({ @ar[$_ % @ar.elems] }).[0..100]
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a ...)
一个更酷的(我认为)解决方案是让你首先将你的列表变成 slip, and then apply the repetition operator 无限期地到那个滑动:
> my @ar=<a b c>
[a b c]
> (|@ar xx *).[0..100]
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a ...)
结论
尽管我可以做到这一点(尤其是最后一个解决方案非常简洁和令人满意),但我想知道我是否遗漏了专门为此目的而内置的任何东西。
编辑回复:接受的答案
这是对@Brad Gilbert 的回答稍加阐述。 «~»
运算符包装 string concatenation ~
in the « »
hyper operator,这导致将包装的二元运算符应用于从两个列表中按顺序选择的元素。
所以为了实现我想要的(列表循环到所需的长度,比如 100),一个人会做
<a b c> <<~>> ("" xx 100)
这会产生
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a)
(100 个条目)。它确实有一些缺点:
- 由于
~
的应用,它将列表条目强制转换为字符串
- 它实际上并没有产生惰性无限列表:
<a b c> <<~>> ("" xx *)
returns
List on right side of hyperop of infix:<~> is known to be infinite
in block <unit> at <unknown file> line 1
既然能写这么短,为什么还要加个功能。特别是因为它可能是一个罕见的事件,你会需要这样的东西。
|< a b c > xx *
有一个例外,如果您使用 «~»
之类的东西,它会为您扩展。
< a b c > «~» (1..10)
# (a1 b2 c3 a4 b5 c6 a7 b8 c9 a10)
你的第一个“down-to-earth”例子可以写成(^Inf).map({ @ar[$_ % *] })
此外,滑动和重复效果很好,但仅适用于合理大小的列表。
sub bad-cycle(@xs) {
|@xs xx Inf
}
my $big-list = ^1e6;
say bad-cycle($big-list).head(100); # Hangs for several seconds
更好的选择是如上所示的地图,或像这样的 gather
循环
sub cycle(@xs) {
gather loop { .take for @xs }
}
say cycle($big-list).head(100); # Instant output
不知道我有没有看懂问题。但据我了解,您需要一种方法来按照模式生成无限列表。好吧,如果这是问题所在
在书“Think in Raku”中,第 14.5 部分(改编自如何做斐波那契数列)
("a","b","c", -> $a, $b, $c {$a} ...* )
这个元素是 pure-list,如果你想要提取值,你需要列表上更常规的东西(比如分配和提取值)
my @list = ("a","b","c", -> $a, $b, $c {$a} ...* )
@list[0..100]
@list[91]
我认为在 Inf 上下文中使用 map 不是个好主意,但如果我遗漏了什么请告诉我,我也在学习这门很棒的语言!!
这主要是为了了解 Raku 有多棒。
问题
是否有内置方法可以获取一个列表并无限循环它,从而生成惰性列表
a, b, c, a, b, c, ...
出(a, b, c)
? documentation 列表中的任何内容似乎都无法解决问题。
可能的解决方案
我至少能想到几个。
更沉闷的脚踏实地的方法是 map @array[<variable> mod length-of-@array]
在惰性范围 0..Inf
上。在 perl6
REPL 中:
> my @ar=<a b c>
[a b c]
> (0..Inf).map({ @ar[$_ % @ar.elems] }).[0..100]
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a ...)
一个更酷的(我认为)解决方案是让你首先将你的列表变成 slip, and then apply the repetition operator 无限期地到那个滑动:
> my @ar=<a b c>
[a b c]
> (|@ar xx *).[0..100]
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a ...)
结论
尽管我可以做到这一点(尤其是最后一个解决方案非常简洁和令人满意),但我想知道我是否遗漏了专门为此目的而内置的任何东西。
编辑回复:接受的答案
这是对@Brad Gilbert 的回答稍加阐述。 «~»
运算符包装 string concatenation ~
in the « »
hyper operator,这导致将包装的二元运算符应用于从两个列表中按顺序选择的元素。
所以为了实现我想要的(列表循环到所需的长度,比如 100),一个人会做
<a b c> <<~>> ("" xx 100)
这会产生
(a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a b c a)
(100 个条目)。它确实有一些缺点:
- 由于
~
的应用,它将列表条目强制转换为字符串
- 它实际上并没有产生惰性无限列表:
<a b c> <<~>> ("" xx *)
returns
List on right side of hyperop of infix:<~> is known to be infinite
in block <unit> at <unknown file> line 1
既然能写这么短,为什么还要加个功能。特别是因为它可能是一个罕见的事件,你会需要这样的东西。
|< a b c > xx *
有一个例外,如果您使用 «~»
之类的东西,它会为您扩展。
< a b c > «~» (1..10)
# (a1 b2 c3 a4 b5 c6 a7 b8 c9 a10)
你的第一个“down-to-earth”例子可以写成(^Inf).map({ @ar[$_ % *] })
此外,滑动和重复效果很好,但仅适用于合理大小的列表。
sub bad-cycle(@xs) {
|@xs xx Inf
}
my $big-list = ^1e6;
say bad-cycle($big-list).head(100); # Hangs for several seconds
更好的选择是如上所示的地图,或像这样的 gather
循环
sub cycle(@xs) {
gather loop { .take for @xs }
}
say cycle($big-list).head(100); # Instant output
不知道我有没有看懂问题。但据我了解,您需要一种方法来按照模式生成无限列表。好吧,如果这是问题所在 在书“Think in Raku”中,第 14.5 部分(改编自如何做斐波那契数列)
("a","b","c", -> $a, $b, $c {$a} ...* )
这个元素是 pure-list,如果你想要提取值,你需要列表上更常规的东西(比如分配和提取值)
my @list = ("a","b","c", -> $a, $b, $c {$a} ...* )
@list[0..100]
@list[91]
我认为在 Inf 上下文中使用 map 不是个好主意,但如果我遗漏了什么请告诉我,我也在学习这门很棒的语言!!