请参阅@wamba 的精彩回答,了解您标题中问题的解决方案。它们展示了各种适用的 Raku 结构。
此答案侧重于 Raku 的序列运算符 (...),以及您问题正文中的详细信息,解释您的尝试中出了什么问题,并解释了一些工作序列。
TL;DR
Nth 项的值为1 / N。
# Generator ignoring prior terms, incrementing an N stored in the generator:
{ 1 / ++$ } ... * # idiomatic
{ state $N; $N++; 1 / $N } ... * # longhand
# Generator extracting denominator from prior term and adding 1 to get N:
1/1, 1/2, 1/3, 1/(*.denominator+1) ... * # idiomatic (@jjmerelo++)
1/1, 1/2, 1/3, {1/(.denominator+1)} ... * # longhand (@user0721090601++)
{1/$_} 有什么问题?
1, 1/2, 1/3, 1/4 ... *
Nth 的值是多少?我是1/N。
1, {1/$_} ...*
Nth 的值是多少?我是1/$_。
$_ 是一个通用的参数/参数/操作数,类似于英文代词“it”。
是否设置为N?
没有。
因此您的生成器(lambda/函数)不会对您尝试复制的序列进行编码。
$_ 设置为什么?
在函数内,$_ 绑定到 (Any) 或传递给函数的参数。
如果一个函数显式指定它的参数(“参数”指定一个函数期望接收的参数;这与函数实际结束的参数不同对于任何给定的呼叫),那么$_ 是根据该规范绑定或不绑定的。
如果一个函数没有显式指定它的参数——而你的没有——那么$_将绑定到作为调用的一部分传递的参数(如果有)函数。
对于 generator 函数,作为参数传递的任何值都是 序列中前面的项的值。
鉴于您的生成器没有明确指定其参数,如果有的话,前一个术语将被传递并绑定到$_。
在生成器的第一次调用中,当1/$_ 被评估时,$_ 绑定到第一个术语的1。所以第二个词是1/1,即1。
因此,产生第三项的 second 调用具有相同的结果。所以你会得到一个无限的1s 序列。
{1/@list[$_+1]} 有什么问题?
对于您的最后一个示例,您大概是指:
my @list = 0 ... *;
(1, {1/@list[$_+1]} ...*)[0..5]
在这种情况下,生成器的 first 调用返回1/@list[1+1],即1/2 (0.5)。
所以第二个调用是1/@list[0.5+1]。这指定了@list 的小数索引,要求1.5th 元素。标准Positionals 的索引向下舍入到最接近的整数。所以1.5 向下舍入为1。 @list[1] 的计算结果为 1。所以第二次调用生成器返回的值又回到了1。
因此,序列在1 和0.5 之间交替。
将哪些参数传递给生成器?
Raku 将序列中零个或多个先前项的值作为参数传递给生成器。
有多少?好吧,生成器是一个普通的 Raku lambda/函数。 Raku 使用参数的隐式或显式声明来确定要传递多少个参数。
例如,在:
{42} ... * # 42 42 42 ...
lambda 没有声明它有什么参数。对于此类功能,Raku 假定签名包括$_?,因此如果有的话,会通过先前的术语。 (上面的 lambda 忽略它。)
您需要/希望您的生成器传递哪些参数?
有人可能会争辩说,对于您要生成的序列,您不需要/不想传递 任何 的先前术语。因为,可以说,它们都不真正重要。
从这个角度来看,重要的是Nth 项计算1/N。也就是说,它的值与先前项的值无关,仅取决于计算调用次数。
状态解决方案如{1/++$}
一种计算方法如下:
{ state $N; $N++; 1/$N } ... *
lambda 忽略前一项。最终结果就是想要的1 1/2 1/3 ...。
(除非您必须摆弄字符串化,因为默认情况下它将使用gist,这会将1/3 转换为0.333333 或类似的。)
或者,更简洁/惯用:
{ 1 / ++$ } ... *
(语句/表达式中的匿名$ 是同时声明和使用匿名状态标量变量。)
使用前项的解决方案
正如@user0721090601++ 在下面的评论中指出的那样,可以编写一个利用先前值的生成器:
1/1, 1/2, 1/3, {1/(.denominator+1)} ... *
对于没有明确指定其参数的生成器,Raku 将序列中前一项的值作为参数传递,将其绑定到“it”参数$_。
鉴于.denominator 没有显式调用者,Raku 假定您的意思是调用$_ 上的方法。
正如@jjmerelo++ 所说,表达许多 lambda 表达式的惯用方式是使用显式代词“whatever”而不是“it”(隐式或显式)来形成 WhateverCode lambda:
1/1, 1/2, 1/3, 1/(*.denominator+1) ... *
你可以去掉这个表格的大括号,这是它的优点之一。 (您也可以在一个表达式中使用多个“whatevers”,而不仅仅是一个“it”,这是该构造的另一部分魅力。)
这种结构通常需要一些时间来适应;也许最大的障碍是* 必须与“WhateverCodeable”运算符/函数结合起来才能形成WhateverCode lambda。