met*_*gib 14 lazy-sequences raku
我想生成的序列
1, 1/2, 1/3, 1/4 ... *
Run Code Online (Sandbox Code Playgroud)
在 raku 中使用函数式编程方法,在我的脑海中它应该是这样的:
(1,{1/$_} ...*)[0..5
]
但输出是: 1,1,1,1,1 这个想法很简单,但对我来说似乎足够强大,可以用来生成其他复杂的列表并使用它。
我尝试过的其他事情是使用惰性列表在其他惰性列表中调用,它也不起作用,因为输出是重复序列:1, 0.5, 1, 0.5 ...
my list = 0 ... *;
(1, {1/@list[$_]} ...*)[0..5]
Run Code Online (Sandbox Code Playgroud)
rai*_*iph 14
请参阅@wamba 对标题中问题的解决方案的精彩回答。他们展示了广泛的适用 Raku 结构。
此答案侧重于 Raku 的序列运算符 ( ...
),以及问题正文中的详细信息,解释了您尝试中出现的问题,并解释了一些工作序列。
N
第 th 项的值是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++)
Run Code Online (Sandbox Code Playgroud)
{1/$_}
?1, 1/2, 1/3, 1/4 ... *
Run Code Online (Sandbox Code Playgroud)
N
第 th 项的值是多少?它是1/N
。
1, {1/$_} ...*
Run Code Online (Sandbox Code Playgroud)
什么是价值 N
第 th 项多少?它是1/$_
。
$_
是通用的 类似于英语代词“it”参数/参数/操作数。
是否设置为 N
?
不。
因此,您的生成器(lambda/函数)不会对您尝试重现的序列进行编码。
$_
设置?在函数内,$_
绑定到(Any)
,或传递给函数的参数。
如果一个函数显式地指定了它的参数(一个“参数”指定了一个函数期望接收的参数;这与一个函数实际上最终获得的任何给定调用的参数不同),那么$_
是绑定或不绑定,每个那个规格。
如果一个函数没有明确指定它的参数——而你的没有——那么$_
绑定到参数,如果有的话,它作为函数调用的一部分传递。
对于生成器函数,作为参数传递的任何值都是序列中前面项的值。
鉴于您的生成器没有明确指定其参数,如果有的话,前一项将被传递并绑定到 $_
。
在您的生成器的第一次调用中,当1/$_
被评估时,$_
绑定到1
来自第一项的 。所以第二项是1/1
,即1
。
因此,产生第三项的第二次调用具有相同的结果。所以你得到一个无限的序列1
s。
{1/@list[$_+1]}
?对于您的最后一个示例,您大概的意思是:
my @list = 0 ... *;
(1, {1/@list[$_+1]} ...*)[0..5]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,生成器的第一次调用返回的1/@list[1+1]
是1/2
( 0.5
)。
所以第二个调用是1/@list[0.5+1]
。这指定了一个小数索引到@list
,要求1.5
第 th 个元素。标准Positional
s 的索引向下舍入到最接近的整数。所以1.5
四舍五入为1
。并@list[1]
评估为1
。所以生成器第二次调用返回的值又回到了1
.
因此序列在1
和之间交替0.5
。
Raku 将序列中零个或多个先验项的值作为参数传递给生成器。
多少?好吧,生成器是一个普通的 Raku lambda/函数。Raku 使用隐式或显式参数声明来确定要传递多少个参数。
例如,在:
{42} ... * # 42 42 42 ...
Run Code Online (Sandbox Code Playgroud)
lambda 没有声明它有什么参数。对于这样的函数,Raku 假定一个签名包括$_?
,因此如果有的话,就会通过先前的术语。(上面的 lambda 忽略了它。)
有人可能会争辩说,对于您要生成的序列,您不需要/不想通过任何先前的条款。因为,可以说,没有它们重要。
从这个角度来看,重要的是N
第 th 项计算1/N
。也就是说,它的值与先前项的值无关,仅取决于调用次数。
{1/++$}
计算这个的一种方法是这样的:
{ state $N; $N++; 1/$N } ... *
Run Code Online (Sandbox Code Playgroud)
lambda 忽略前一项。最终结果正是想要的1 1/2 1/3 ...
。
(除了你必须摆弄字符串化,因为默认情况下它会使用gist
which 将变成1/3
into0.333333
或类似的。)
或者,更简洁/惯用地:
{ 1 / ++$ } ... *
Run Code Online (Sandbox Code Playgroud)
($
语句/表达式中的匿名是同时声明和使用匿名状态标量变量。)
正如@user0721090601++ 在下面的评论中指出的那样,可以编写一个使用先验值的生成器:
1/1, 1/2, 1/3, {1/(.denominator+1)} ... *
Run Code Online (Sandbox Code Playgroud)
对于未明确指定其参数的生成器,Raku 将序列中前一项的值作为参数传递,并将其绑定到“it”参数$_
。
并且鉴于没有明确的 for.denominator
调用者,Raku 假定您的意思是在 上调用该方法$_
。
正如@jjmerelo++ 所指出的,表达许多 lambda 表达式的惯用方式是使用显式代词“whatever”而不是“it”(隐式或显式)来形成WhateverCode
lambda:
1/1, 1/2, 1/3, 1/(*.denominator+1) ... *
Run Code Online (Sandbox Code Playgroud)
您可以放弃这种形式的大括号,这是它的优点之一。(您也可以在一个表达式中使用多个“whatevers”,而不仅仅是一个“it”,这是该结构魅力的另一部分。)
这种构造通常需要一些时间来适应;也许最大的障碍是 a*
必须与“WhateverCode
能够”的运算符/函数结合才能形成WhateverCode
lambda。
wam*_*mba 14
(1..*).map: 1/*
Run Code Online (Sandbox Code Playgroud)
1/++$ xx *
Run Code Online (Sandbox Code Playgroud)
1 X/ 1..*
1 xx * Z/ 1..*
Run Code Online (Sandbox Code Playgroud)
gather for 1..* { take 1/$_ }
Run Code Online (Sandbox Code Playgroud)
Seq.from-loop: { 1/++$ }
Run Code Online (Sandbox Code Playgroud)
1, 1/(1+1/*) ... *
{1/++$} ... *
Run Code Online (Sandbox Code Playgroud)