如何生成惰性除法?
How to generate a lazy division?
我要生成
的序列
1, 1/2, 1/3, 1/4 ... *
在 raku 中使用函数式编程方法,在我看来它应该是这样的:
(1,{1/$_} ...*)[0..5
]
但输出是:1,1,1,1,1
这个想法很简单,但似乎足以让我用来生成其他复杂列表并使用它。
我尝试的其他事情是使用惰性列表在其他惰性列表中调用,它也不起作用,因为输出是一个重复序列:1, 0.5, 1, 0.5 ...
my list = 0 ... *;
(1, {1/@list[$_]} ...*)[0..5]
查看@wamba 的精彩解答,了解您标题中问题的解答。他们展示了广泛适用的 Raku 结构。
此答案主要关注 Raku 的序列运算符 (...
),以及您问题 body 中的详细信息,解释您的尝试中出现的错误,并解释一些工作序列。
TL;DR
第 N
项的值为 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 ... *
第 N
项的值是多少?这是 1/N
.
1, {1/$_} ...*
第 N
项的值是多少?这是 1/$_
.
$_
是通用的 parameter/argument/operand 类似于英语代词“it”。
是否设置为N
?
没有
因此您的生成器 (lambda/function) 不会对您尝试重现的序列进行编码。
$_
设置了什么?
在函数中,$_
绑定到 (Any)
,或绑定到传递给函数的参数。
如果一个函数明确指定了它的参数(一个“参数”指定了一个函数期望接收的实参;这是不同的从一个函数实际上最终获得任何给定调用的参数),然后 $_
根据该规范绑定或不绑定。
如果一个函数没有明确指定它的参数——而你的没有——然后$_
被绑定到参数,如果有的话,那就是作为函数调用的一部分传递。
对于 generator 函数,作为参数传递的任何值都是 序列中前面项的值。
鉴于您的生成器未明确指定其参数,如果有的话,紧接在前的术语将被传递并绑定到 $_
。
在生成器的 first 调用中,当 1/$_
被求值时,$_
从第一个开始就绑定到 1
学期。所以第二项是1/1
,即1
.
因此,产生第三项的 second 调用具有相同的结果。所以你得到一个无限的 1
s.
序列
{1/@list[$_+1]}
怎么了?
对于你的最后一个例子,你大概是指:
my @list = 0 ... *;
(1, {1/@list[$_+1]} ...*)[0..5]
在这种情况下,生成器 returns 1/@list[1+1]
的 第一次 调用是 1/2
(0.5
)。
所以 第二个 调用是 1/@list[0.5+1]
。这指定 @list
的小数索引,要求第 1.5
个元素。标准 Positional
的索引向下舍入到最接近的整数。所以 1.5
向下舍入为 1
。 @list[1]
的计算结果为 1
。所以第二次调用生成器返回的值又回到了1
.
因此序列在 1
和 0.5
之间交替。
传递给生成器的参数是什么?
Raku 将序列中零个或多个先验项的值作为参数传递给生成器。
有多少?好吧,发电机就是普通的 Raku lambda/function。 Raku 使用参数的隐式或显式声明来确定要传递多少参数。
例如,在:
{42} ... * # 42 42 42 ...
lambda 没有声明它有什么参数。对于此类函数,Raku 假定签名包括 $_?
,因此通过了先前的术语(如果有的话)。 (上面的 lambda 忽略它。)
你need/want你的生成器要传递哪些参数?
有人可能会争辩说,对于您打算生成的序列,您不会 need/want 传递 任何 的先验项。因为,可以说,none 确实很重要。
从这个角度来看,重要的是第 N
项计算 1/N
。也就是说,它的值独立于先验项的值,仅取决于计算调用次数。
陈述解决方案,例如{1/++$}
一种计算方法如下:
{ state $N; $N++; 1/$N } ... *
lambda 忽略前一项。最终结果正是我们想要的 1 1/2 1/3 ...
.
(除非你必须 fiddle 进行字符串化,因为默认情况下它会使用 gist
这会将 1/3
变成 0.333333
或类似的.)
或者,更多 succinctly/idiomatically:
{ 1 / ++$ } ... *
(statement/expression 中的匿名 $
是同时声明和使用匿名状态标量变量。)
使用先验项的解决方案
正如@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”,这是这个结构的另一个魅力所在。)
这个构造通常需要一些时间来适应;也许最大的障碍是 *
必须与“WhateverCode
able”operator/function 组合才能形成 WhateverCode
lambda。
(1..*).map: 1/*
1/++$ xx *
The cross metaoperator, X
or the zip metaoperator Z
1 X/ 1..*
1 xx * Z/ 1..*
(Control flow) control flow gather take
gather for 1..* { take 1/$_ }
Seq.from-loop: { 1/++$ }
1, 1/(1+1/*) ... *
{1/++$} ... *
我要生成
的序列1, 1/2, 1/3, 1/4 ... *
在 raku 中使用函数式编程方法,在我看来它应该是这样的:
(1,{1/$_} ...*)[0..5
]
但输出是:1,1,1,1,1 这个想法很简单,但似乎足以让我用来生成其他复杂列表并使用它。
我尝试的其他事情是使用惰性列表在其他惰性列表中调用,它也不起作用,因为输出是一个重复序列:1, 0.5, 1, 0.5 ...
my list = 0 ... *;
(1, {1/@list[$_]} ...*)[0..5]
查看@wamba 的精彩解答,了解您标题中问题的解答。他们展示了广泛适用的 Raku 结构。
此答案主要关注 Raku 的序列运算符 (...
),以及您问题 body 中的详细信息,解释您的尝试中出现的错误,并解释一些工作序列。
TL;DR
第 N
项的值为 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 ... *
第 N
项的值是多少?这是 1/N
.
1, {1/$_} ...*
第 N
项的值是多少?这是 1/$_
.
$_
是通用的 parameter/argument/operand 类似于英语代词“it”。
是否设置为N
?
没有
因此您的生成器 (lambda/function) 不会对您尝试重现的序列进行编码。
$_
设置了什么?
在函数中,$_
绑定到 (Any)
,或绑定到传递给函数的参数。
如果一个函数明确指定了它的参数(一个“参数”指定了一个函数期望接收的实参;这是不同的从一个函数实际上最终获得任何给定调用的参数),然后 $_
根据该规范绑定或不绑定。
如果一个函数没有明确指定它的参数——而你的没有——然后$_
被绑定到参数,如果有的话,那就是作为函数调用的一部分传递。
对于 generator 函数,作为参数传递的任何值都是 序列中前面项的值。
鉴于您的生成器未明确指定其参数,如果有的话,紧接在前的术语将被传递并绑定到 $_
。
在生成器的 first 调用中,当 1/$_
被求值时,$_
从第一个开始就绑定到 1
学期。所以第二项是1/1
,即1
.
因此,产生第三项的 second 调用具有相同的结果。所以你得到一个无限的 1
s.
{1/@list[$_+1]}
怎么了?
对于你的最后一个例子,你大概是指:
my @list = 0 ... *;
(1, {1/@list[$_+1]} ...*)[0..5]
在这种情况下,生成器 returns 1/@list[1+1]
的 第一次 调用是 1/2
(0.5
)。
所以 第二个 调用是 1/@list[0.5+1]
。这指定 @list
的小数索引,要求第 1.5
个元素。标准 Positional
的索引向下舍入到最接近的整数。所以 1.5
向下舍入为 1
。 @list[1]
的计算结果为 1
。所以第二次调用生成器返回的值又回到了1
.
因此序列在 1
和 0.5
之间交替。
传递给生成器的参数是什么?
Raku 将序列中零个或多个先验项的值作为参数传递给生成器。
有多少?好吧,发电机就是普通的 Raku lambda/function。 Raku 使用参数的隐式或显式声明来确定要传递多少参数。
例如,在:
{42} ... * # 42 42 42 ...
lambda 没有声明它有什么参数。对于此类函数,Raku 假定签名包括 $_?
,因此通过了先前的术语(如果有的话)。 (上面的 lambda 忽略它。)
你need/want你的生成器要传递哪些参数?
有人可能会争辩说,对于您打算生成的序列,您不会 need/want 传递 任何 的先验项。因为,可以说,none 确实很重要。
从这个角度来看,重要的是第 N
项计算 1/N
。也就是说,它的值独立于先验项的值,仅取决于计算调用次数。
陈述解决方案,例如{1/++$}
一种计算方法如下:
{ state $N; $N++; 1/$N } ... *
lambda 忽略前一项。最终结果正是我们想要的 1 1/2 1/3 ...
.
(除非你必须 fiddle 进行字符串化,因为默认情况下它会使用 gist
这会将 1/3
变成 0.333333
或类似的.)
或者,更多 succinctly/idiomatically:
{ 1 / ++$ } ... *
(statement/expression 中的匿名 $
是同时声明和使用匿名状态标量变量。)
使用先验项的解决方案
正如@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”,这是这个结构的另一个魅力所在。)
这个构造通常需要一些时间来适应;也许最大的障碍是 *
必须与“WhateverCode
able”operator/function 组合才能形成 WhateverCode
lambda。
(1..*).map: 1/*
1/++$ xx *
The cross metaoperator, X
or the zip metaoperator Z
1 X/ 1..*
1 xx * Z/ 1..*
(Control flow) control flow gather take
gather for 1..* { take 1/$_ }
Seq.from-loop: { 1/++$ }
1, 1/(1+1/*) ... *
{1/++$} ... *