【问题标题】:rank operator vs axis notation秩运算符与轴符号
【发布时间】:2018-02-08 14:26:08
【问题描述】:

几年前,我在大型机上偷看了 APL2,并记得当时向我展示了向矩阵添加向量的问题的解决方案。

给定a←4 4 ⍴ ⍳16⎕io←1

向行添加向量的旧方法类似于

a+(⍴a)⍴10 20 30 40

导致

11 22 33 44
15 26 37 48
19 30 41 52
23 34 45 56

将向量添加到矩阵的列是

a+(4 1⍴10 20 30 40)[;1 1 1 1]

或者,如果你愿意,

a+4/4 1⍴10 20 30 40

导致

11 12 13 14
25 26 27 28
39 40 41 42
53 54 55 56

幸运的是,我能够打电话给那天向我展示 APL2 的那个人(他已经退休但仍然接听电话)并询问第二个解决方案,他立刻想起了我在说什么。

新的 APL2 方法更加简洁、简洁和一致,这些示例将由 a+[2] 10 20 30 40a+[1] 10 20 30 40 解决。凉爽的。它在 Dyalog 中有效。

快进十年或更长时间,我发现有一个新事物叫做排名运算符。第一个例子可以a(+⍤1) 10 20 30 40解决(我还在努力掌握括号的用法,我想一旦我明白了一点,我就真的再生了一些脑细胞)

尽管如此,没有直接的(至少对我而言)类似于第二个示例a+[1] 10 20 30 40 使用排名运算符。我不能说我完全理解它,但在我看来,秩运算符通过折叠它的维度来“重新转换”它的左参数,同时保持内容完整。太多年的 C++ 和 Java 影响了我的思考方式。

对于a+[1] 10 20 30 40 使用排名运算符有简单的解决方案吗?到目前为止,我发现的唯一想法是⍉(⍉a)(+⍤1) 10 20 30 40,它没有抓住重点,违背了整个目的。

为什么秩运算符比轴表示法更可取?哪个更好”? (可以肯定的是,这是一个加载的术语)乍一看,轴符号对我这个鞋码智商的人来说很容易掌握。对于排名运算符,我不能说同样的话。

【问题讨论】:

    标签: apl dyalog


    【解决方案1】:

    对于a+[1] 10 20 30 40,有没有使用秩运算符的简单解决方案?

    是的:a(+⍤1 0)10 20 30 40Try it online!
    对于二元应用程序,秩运算符实际上需要一个两个元素的右操作数(但接受一个扩展为两个元素的单例)。 a(f⍤A B)b 表示 a 的 rank-A 子数组应与 b 的 rank-B 子数组配对。因此,在您的情况下,a(+⍤1)10 20 30 40(实际上是指a(+⍤1 1)10 20 30 40)表示应将a(行)的rank-1数组添加到10 20 30 40的rank-1数组(整个向量)。这里,a(+⍤1 0)10 20 30 40 表示 a(行)的 rank-1 数组应该添加到 10 20 30 40(标量)的 rank-0 数组中。

    为什么秩运算符比轴表示法更可取?

    rank 运算符允许您完全控制从每个参数中获取的内容,而括号轴表示法只允许您扩展较低级别的参数。秩运算符是语言的一个组成部分,可以与任何函数一起使用,甚至是用户定义的函数,而括号轴表示法只能与二元标量函数、归约函数和一小部分混合函数一起使用。

    哪个“更好”?

    由于等级运算符遵循运算符的正常 APL 语法并且普遍适用,因此它减少了要记住的规则数量。此外,排名运算符还允许通过使用负数来指定相对排名。因此,⍤1 表示 应用于等级为 1 的子数组⍤¯1 表示应用于比整个参数低一级的子数组。在我看来,这足以安全地认为秩运算符比括号轴“更好”。

    我仍在努力掌握括号的用法

    我个人不喜欢括号,所以我知道你从哪里来。幸运的是,您可以随意减少括号的数量。 a(+⍤1)10 20 30 40 中括号的唯一原因是将数组操作数1 与数组参数10 20 30 40 分开。任何其他分离它们的方法也是可以接受的,我通常使用标识函数a+⍤1⊢10 20 30 40Try it online!
    但是,您也可以将 curry right operands 转换为二元运算符,生成一元运算符,读起来非常好:horizontally←⍤1 0 ⋄ vertically←⍤1 1 Try it online!

    完整的rank operator documentation is available online

    【讨论】:

    • 感谢您出色的全面回复。我仍然缺少一些脑细胞,但它正在变得更好。我发现恒等函数构造有点奇怪,因为在我看来 a+⍤1⊢10 20 30 40 的左参数被消耗了两次,首先是评估 1⊢10 20 30 40 (返回右参数),然后是 @987654352 的一部分@ 运算符表达式。我真的很喜欢咖喱,即使它有点 Haskell 的味道。易于理解和解释。
    • @Apollo42 请记住,运算符在函数之前绑定,因此1 在有机会在 的左参数之前被“捕获”,而 是因此 - 称为单子。顺便说一句,the Stack Exchange APL chat room 随时​​欢迎您。
    【解决方案2】:

    多年来,一种流行的观点是应避免使用方括号,即函数的索引和轴“运算符”。造成这种情况的一些原因是方括号语法异常并且与语言的其余部分不一致,方括号内参数的语义在函数组之间不同,它使解析复杂化等等。 Google "apl axis operator anomalous" 有很多例子。

    索引

    旧版索引是熟悉的 x[i] 形式,替代方法包括 "pick" 和 "squad" 函数。更高维度的索引数组使用x[i;j;k;...;n] 形式,其中; 分隔各个维度表达式。这个表达可以省略以表示“所有那个维度”。然后是索引赋值,可以选择性地插入新值。

    轴操作员

    首先只规定了轴规格减少+/[1]a,压缩b/[1]a,扩展b\[1]a,最后旋转1⌽[2]x 和反向⌽[2]x。稍后扫描+\a,连接x,[1] y 和层压x,[0.5] y 也是如此。 (浮点“轴”- 好悲哀)APL2 引入了更多与您的示例 a +[2] b 不同的案例,并包含在任意坐标 ⊂[2] 上。

    秩运算符提供了一种统一的方式来处理坐标规范。

    【讨论】:

      【解决方案3】:

      我认为,要向矩阵添加向量,您不应再使用秩运算符搜索更简单的解决方案。我想引入秩运算符是为了实现原始标量函数的行为,也适用于定义的函数。也就是说,如果你有一个定义的函数,比如说

      ∇Z←A ADD B
       Z←A + B
      ∇
      

      然后

      a ADD[1] 10 20 30 40
      

      会失败并迫使您使用排名运算符。 rank 运算符需要括号,因为它的语法有些可疑:

      a +⍤1 10 20 30 40    ⍝ ???
      a(+⍤1)10 20 30 40    ⍝ maybe this?
      a(+⍤1 10) 20 30 40   ⍝ or maybe this?
      a(+⍤1 10 20) 30 40   ⍝ or even this?
      

      IBM 足够聪明,可以标准化秩运算符,但没有实现它(至少在我的 PC 演示版 APL2 中)。

      【讨论】:

      • 你说的 IBM 足够聪明,可以标准化秩运算符但没有实现它是什么意思? AFAIK IBM 在嵌套阵列系统的初始实施后从未向 APL2 添加任何功能。此外,语法可疑的不是 rank 运算符。它遵循与所有其他运算符相同的语法。相反,是 APL 的绞合使相邻的阵列模糊在一起。如果没有链符号,a +⍤1 (10,20,30,40) 将是明确的。
      • 我的意思是 IBM 编写了大部分 ISO APL2 标准(它定义了等级运算符),但他们自己并没有实现它。如果运算符的函数参数可以是值,则有些人(包括我自己)认为这是一种“黑客行为”。这是有效的,但看起来很奇怪。例如问题+⍤1 2 3 4 是在 APL2 中 1 比其他的绑定更强,所以它意味着 (+⍤1) 2 3 4 如果您不熟悉确切的绑定规则,则很难理解。而1(在ISO标准中称为y可以有1、2或3个元素,但没有()只能实现1元素的情况。
      • 好的,这奇怪的。 Dyalog 的等级操作符是完全正则的,并且比操作符绑定更搁浅is always stronger。允许数组操作数使得像⍣ ∘ ⍤ @ ⍠ ⌺ 这样的操作符成为可能,而且确实非常强大。
      • 事实上,IBM APL2、MicroAPL 和 GNU APL 使用相同的绑定规则集,而 Dyalog APL 使用不同的绑定规则。出于这个原因,尝试尽可能多地删除括号并不总是一个好主意,即使代码看起来更简洁一些。在 ⍤ 删除括号的上下文中,您的代码的可移植性降低,因此可用性降低。
      • 实际上,Dyalog 的语法移植到其他系统,反之则不然。
      猜你喜欢
      • 2013-09-27
      • 2018-12-08
      • 2010-10-10
      • 2020-04-22
      • 1970-01-01
      • 1970-01-01
      • 2011-04-20
      • 2017-03-29
      • 1970-01-01
      相关资源
      最近更新 更多