【问题标题】:Is it possible to chain metaoperators to calculate the product-sum of two lists in Raku?是否可以链接元运算符来计算 Raku 中两个列表的乘积和?
【发布时间】:2021-05-18 20:36:34
【问题描述】:

我正在学习 Raku,但有些事情让我感到困惑。

为了计算两个列表的元素乘积之和(至少其中一个是有限的),我希望能够写出类似的东西

@a Z*[+] @b

但它没有给出预期的结果。

使用[+] @a Z* @b 表单按预期工作

> my @a = 2...6;
[2 3 4 5 6]
> my @b = 5...1;
[5 4 3 2 1]
> @a Z @b;
((2 5) (3 4) (4 3) (5 2) (6 1))
> @a Z* @b;
(10 12 12 10 6)
> [+] @a Z* @b
50

但是当我将Z*[+] 链接在一起时它不喜欢它

> @a Z*[+] @b
(30)
> @a Z*+ @b                           
(10)
> @a +Z* @b
===SORRY!=== Error while compiling:
Undeclared name:
    Z used at line 1

> @a +[Z*] @b
6
> @a [Z*]+ @b
(10)
> @a [Z*][+] @b
(30)

我想这里存在一些优先级问题,但在 Raku 文档中找不到足够的示例。

我还发现了 >>*<< 的无法解释的行为:

> [+] @a >>*<< @b
50
> @a [+][>>*<<] @b
125
> @a [>>*<<][+] @b
Lists on either side of non-dwimmy hyperop of infix:<*> are not of the same length while recursing
left: 5 elements, right: 1 elements
  in block <unit> at <unknown file> line 1

问题

  • 是否可以通过这种方式评估两个列表的积和?
  • 不同的链式变体发生了什么导致6(10)(30)125 等结果?

【问题讨论】:

    标签: operators raku


    【解决方案1】:

    是否可以通过这种方式评估两个列表的积和?

    是的。

    让我们从链接开始:

    • 可以编写从右到左链接的 Raku 代码,但我们会坚持从左到右。

    • 您所谓的“产品总和”的从左到右的英文阅读将是这些 列表的元素的 products 的“sum >”。所以我们想在左边求和,下一个产品,最后一个列表。

    有一个内置的sum,但没有内置的product,所以我们需要处理后者。一种方法是将[Z*] 写为reduction(这意味着它必须出现在它减少的列表的左侧)。另一种是写一个新的product函数。

    综上所述,以下是我们可以编写“乘积总和”的一些方法:

    say [+] [Z*]             @a, @b;  # 50  (closest to what it seems you want)
    say sum [Z*]             @a, @b;  # 50  (`sum` is idiomatic)
    say sum zip :with(&[*]), @a, @b;  # 50  (some prefer `zip :with(&[*])` over `[Z*]`)
    say sum product          @a, @b;  # 50  (requires a user defined `sub`)
    
    sub product (|lists) { zip :with(&[*]), |lists }
    

    按照上述方式进行操作意味着您可以使用任意数量的列表,而不仅仅是两个。

    如果您真的想坚持使用中缀表示法,这会将您限制为两个列表,您可以对产品部分执行此操作:

    say [+] @a  Z*   @b;      # 50    (using infix sequential shallow zip metaop)
    say [+] @a >>*<< @b;      # 50    (using infix parallel nesting hyper metaop)
    
    say sum @a  Z*   @b;      # 50    (replacing `sum` with `[+]` reduction)
    say sum @a >>*<< @b;      # 50
    

    不同的链式变体发生了什么导致6(10)(30)125 等结果?

    Raku 正确地执行了您的代码所表达的内容。

    以下代码示例解释了@Zaid 共享的所有代码/结果。你(任何读者,不仅仅是@Zaid)可能需要做一些工作来理解为什么;如果您无法弄清楚这些示例如何解释 Zaid 的一个或多个结果,请发表评论,我很乐意在评论中解释和/或更新此答案,并感谢您的问题/评论。

    say my @a = 2...6;          # [2 3 4 5 6]
    say my @b = 5...1;          # [5 4 3 2 1]
    
    
    say [+] [5,4,3,2,1];        # 15
                                # Same as:
    say sum @b;                 # 15
    
    
    say 2           Z* 15;      # (30)
                                # zip stops once shortest list exhausted, so same as:
    say [2,3,4,5,6] Z* 15;      # (30)
    
    
    say +@b;                    # 5
                                # `+` coerces argument(s) to number, so short for:
    say elems @b;               # 5
                                # Same as:
    say elems [5,4,3,2,1];      # 5
    
    
    say 2 Z* 5;                 # (10)
    
    
    #say +foo;                  # Error while compiling: Undeclared ... foo
                                # Same effect as:
    #say foo;                   # Error while compiling: Undeclared ... foo
    
    
    say [Z*] @b;                # (120)
                                # Same as:
    say 5 Z* 4 Z* 3 Z* 2 Z* 1;  # (120)
    
    
    say @a [Z*] 5;              # (10)
                                # square brackets redundant, and
                                # zip stops once shortest list exhausted, so same as:
    say 2   Z*  5;              # (10)
    
    
    say [+] @a >>*<< @b;        # 50
    
    
    say [>>*<<] @b;             # 120
                                # hypers redundant if both args scalars, so same as:
    say   [*]   [5,4,3,2,1];    # 120
                                # (5 * 4 * 3 * 2 * 1)
    
    
    say @a [+] [>>*<<] @b;      # 125
                                # square brackets round infix `+` redundant, so same as:
    say @a  +  [>>*<<] @b;      # 125
                                # hypers redundant if both args scalars, so same as:
    say 5   +    [*]   @b;      # 125      (5 + 120)
    
    
    say @a [>>*<<][+]  @b;      # Same as:
    say @a [>>*<<] [+] @b;      #
    say @a [>>*<<] sum @b;      #
    say @a  >>*<<  sum @b;      #
    #say @a  >>*<<  15;         # Lists on either side ... not of the same length
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 2017-04-07
    • 2019-10-08
    相关资源
    最近更新 更多