在 Dyalog 中创建闭包向量

Creating a vector of closures in Dyalog

我想定义一个接受单个参数的匿名函数向量,然后将参数 x 映射到该向量,返回每个索引的 f(x) 结果数组。这在 Dyalog 中可行吗?

我问是因为我天真的尝试创建这样一个闭包向量:

fs ← {⍵×2} {⍵×4} {⍵×8}

行为异常。尝试引用 fs 的单个索引似乎引用了所有索引并使输出出现乱码:

 fs[1]
   ∇{⍵×2}
 ∇       ∇{⍵×4}
 ∇       ∇{⍵×8}
 ∇  [ 1

⍴fs returns 类似的输出而不是 3,这让我相信我根本没有制作数组。解决这个问题的正确方法是什么?

不幸的是,这在 Dyalog 中是不可能的。你在那里做的确实不是一个数组,一个fgh-fork, which is a train of functions f g h that, when called monadically like (f g h)Y, behaves like (f Y)g h Y. If there is a function to the exact left of the left bracket ([) instead of an array, then this is not bracketed indexing, but the axis operator。但是,轴运算符只能应用于一些原始函数,以及从 /\ 派生的函数,因此如果像那样应用于您的功能。

⍴fs 同样是一个函数序列,在本例中是一个顶层,而不是 return fs 的形状,因为 fs 是一个函数。

但是,即使函数不是 APL 中的 first-class 对象,您也可以以某种方式滥用序列,使其看起来像是参数实际上映射到一组函数中。为此,让我们定义一个“Function Chain Link”函数FL

FL ← {(⊂⍺),⍵}

所以,假设我们有函数 fgh 和参数 Y,我们想要 return (f Y)(g Y)(h Y).这现在可以写成 (f FL g FL h)Y 了吧?好吧,不,有一个陷阱。最右边出现的 FL 必须替换为 FL∘⊂。不幸的是,这是一个不可避免的麻烦,但至少现在你可以不用每次都提到 Y 了。现在有两种情况:

  • 函数数组(链)的长度为1,即它只包含一个函数f:在这种情况下,您可以简单地使用(⊂f)Y
  • 函数链包含多个函数,假设fgh:现在,你会写(f FL g FL∘⊂h)Y

我建议将此函数的名称保持简短,最多 2 个字符,因为它会被多次使用。

而且,FL 函数是如何工作的? 事实上,它将 结果 链接在一起,而不是函数他们自己。它只是 encloses the result to its left in an array ((⊂⍺)), then concatenate 将结果放在它的右边 (,⍵)。这导致 "prepending" 左侧结果到右侧结果数组,但将它们保持在一起,即不分离其各个元素。第一次在这样的 "chain" 中使用 的原因是因为 FL 无法确定其右侧的数组是正确函数的结果还是结果,因此,通过第一次包含,您可以确保 FL 的正确参数始终是结果数组,而不是会被前置元素破坏的裸结果。

值得注意的是,您也可以二进调用这样的链,在这种情况下,它的所有函数(不是 FL)都将使用相同的两个参数二进调用。例如,X(f FL g FL∘⊂h)Y(X f Y)(X g Y)(X h Y) 相同。但是,您可能希望以单子方式调用某些函数。虽然与手头的问题没有直接关系,但这个 monadic 运算符将使函数忽略它们的左参数(如果有的话),并且对此非常有帮助,只是因为您避免了括号:

M ← {⍺⍺ ⍵}

那么,假设我们有四个函数 fghp,我们想调用 gp monadically,同时保留 fh 的左参数。现在我们已经实现了 M,我们可以这样做,X 是左参数,Y 是右参数:

X(f FL g M FL h FL∘⊂p M)Y

再次,我建议,如果您决定实现这个 monadic 运算符,您应该将其名称的长度保持在 1 个字符以内。

在 Dyalog APL 中创建一个类似于函数数组的结构的另一种方法是创建一个包含函数的名称空间数组。例如:

    nss←⎕NS¨'' '' '' 
    nss.⍎ 'f←{⍵×2}' 'f←{⍵×4}' 'f←{2+⍵×3}' 
    nss.f 11 
22 44 35

    nss[2].f 2
8

dfns 工作区(与 Dyalog APL 一起提供)讨论了 Function Arrays,并提供了多种方法来处理此类问题。

或者,您可以使用以下一元运算符,它作为操作数采用单行函数定义数组 and/or 名称(命名函数可能是多行的)和 returns 函数然后可以应用的数组:

 r←{x}(fns Fns)y;nss;ns
 nss←{⎕NS ⍬}¨fns
 ns←'.(',⍨⍕⎕THIS
 nss.⍎'f←'∘,¨ns∘,¨fns,¨')'
 :If 900⌶⍬
     x←⊢
 :EndIf
 r←x nss.f y

Try it online!