【问题标题】:How to generate a lazy division?如何生成惰性除法?
【发布时间】:2021-02-13 23:46:01
【问题描述】:

我要生成的序列

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]

【问题讨论】:

    标签: raku lazy-sequences


    【解决方案1】:

    请参阅@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

    因此,序列在10.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。

    【讨论】:

    • 如果想要迭代地处理初始值,那么1/1, { 1 / (*.denominator + 1) } ... * 也可以工作
    • @user0721090601,几乎没有卷曲:(1/1, 1 / (*.denominator + 1) ... *)[0..5]
    • 优点@user0721090601。 :) 我已经相应地重写了我的答案。谢谢。
    • jjmerelo:确实 :-) 我在移动设备上思考得太快了
    • 我学到了很多,感谢您抽出时间来解释我的代码有什么问题,这非常有用,并且认为您的精彩回答和@wamba 的回答是非常清晰和惯用的方法做更复杂的列表
    【解决方案2】:

    TIMTOWTDI

    routine map

    (1..*).map: 1/*
    

    List repetition operator xx

    1/++$ xx *
    

    The cross metaoperator, Xthe zip metaoperator Z

    1 X/ 1..*
    1 xx * Z/ 1..*
    

    (Control flow) control flow gather take

    gather for 1..* { take 1/$_ }
    

    (Seq) method from-loop

    Seq.from-loop: { 1/++$ }
    

    (Operators) infix ...

    1, 1/(1+1/*) ... *
    {1/++$} ... *
    

    【讨论】:

    • TIY Seq.from-loop。我
    • Woaaaaaa 这太棒了,比我预期的答案要多。我学到了很多,列表操作员甚至不在我的手表上这样做
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    相关资源
    最近更新 更多