在 APL 中生成没有循环或流控制的斐波那契数列

Generate a fibonacci series with no loops or flow control in APL

有没有一种方法可以在 APL 中使用不需要循环或流控制的单行创建斐波那契数列?

我已经通过使用 的函数和条件测试完成了它,但我觉得必须有一种更优雅、更声明的方式。 example 我发现声称在一行上完成它在 gnu-apl 上不起作用 - 它似乎在正确的轨道上,使用矩阵数学,但我很难跟上,并且无法调整它以使其正常工作。

我正在追求 APL 作为我的第一门真正的编程语言(我喜欢这些符号。我就是喜欢。)我现在正在使用 Project Euler 作为一种更好地熟悉的方式。

另一种方法是使用(相对较新的)幂运算符。 GNU APL 可能支持也可能不支持,它适用于 Dyalog(我使用的是 13.1)和 NGN APL。

尝试

 ({⍵,+/¯2↑⍵} ⍣ 20) (1 1)  

与其他示例一样,迭代是隐藏的,此处使用幂运算符。

表达式

({⍵,+/¯2↑⍵} ⍣ 3) (1 1)

正在做

{⍵,+/¯2↑⍵} {⍵,+/¯2↑⍵} {⍵,+/¯2↑⍵} 1 1

在幕后。

1 1 是种子值,每个连续的 {⍵,+/¯2↑⍵} 只是连接最后两个元素的总和。

您在使用 Dyalog APL 吗?在这种情况下,您应该利用上一个答案所解释的 power 运算符(该答案中的第一段代码来自 Mastering Dyalog APL 一书,p . 416).

具有相同运算符的另一种解决方案是使用矩阵:

(+.×⍣10)⍨ 2 2⍴1 1 1 0

或作为直接函数:

{⊃(+.×⍣⍵)⍨2 2⍴1 1 1 0} 10

如果您不想使用 power 运算符,您仍然可以使用矩阵(下面的代码在 GNU APL 1.5 下测试):

{+.×/⍵⍴⊂2 2⍴1 1 1 0} 10

好吧,我想我已经找到了一种方法来生成长度为 N(而不是第 N 个数字)的 序列 在单个(虽然不是很漂亮的一行APL2):

+/¨(⊂0 0)⍉¨⊖¨(2/¨⍳N)↑¨⊂P←V∘.!V←⍳1+N←20

就像我说的:不太漂亮。 让我试着把它分解成成语:

这是 20 层的帕斯卡三角形:

P←V∘.!V←⍳1+N←20

然后取左上角前N个方格:

(2/¨⍳N)↑¨⊂P 

这个成语returns矩阵的主对角线:

(⊂0 0)⍉

但是我们想要反对角线,所以在此之前我们将使用 翻转所有方块。

最后一步只是将所有反对角线与 +/ 求和。

我也喜欢 APL 的符号,以及它的数组编程能力。其他数组语言可能更强大,例如 J,但它们缺乏 APL 的符号之美和显式语法。

我刚刚在 GNU APL 中尝试了您 link 的示例,它工作正常:

      ↑0 1↓↑+.×/5/⊂2 2⍴1 1 1 0
5
      ↑0 1↓↑+.×/6/⊂2 2⍴1 1 1 0
8
      ↑0 1↓↑+.×/7/⊂2 2⍴1 1 1 0
13

如果您无法让它工作,请确保:

  • 键入(或复制并粘贴)示例中显示的确切符号:特别是 × 是 U+00D7 MULTIPLICATION SIGN,而不是 X; 是 U+2374 APL FUNCTIONAL SYMBOL RHO,不是任何其他希腊 Rho,也绝对不是 P; 是 U+2282 的子集;等等;
  • 测试 1 或 5 以外的一些数字,因为它们是唯一等于其斐波那契数的数字;
  • 如果您没有用实际数字代替 N,请确保以正确的方式定义 N,例如在前一行中单独定义 N←7

如果您仍然无法使用它,请从右边开始一步一步地输入公式:

      2 2⍴1 1 1 0
1 1
1 0
      ⊂2 2⍴1 1 1 0
 1 1 
 1 0 
      7/⊂2 2⍴1 1 1 0
 1 1   1 1   1 1   1 1   1 1   1 1   1 1 
 1 0   1 0   1 0   1 0   1 0   1 0   1 0 
      +.×/7/⊂2 2⍴1 1 1 0
 21 13 
 13  8 
      ↑+.×/7/⊂2 2⍴1 1 1 0
21 13
13  8
      0 1↓↑+.×/7/⊂2 2⍴1 1 1 0
13
 8
      ↑0 1↓↑+.×/7/⊂2 2⍴1 1 1 0
13

至于问题标题,我认为这个矩阵公式很到位(太棒了@mappo!)

如果我是 golfing,我可能会使用更短的变体,但仅此而已:

      2⌷∊+.×/7/⊂∘.∨⍨1 0
13

那里,从 24 到 17 个字符。看看你能不能想出来:-)

GNU APL 还不错,虽然它缺少一些现代功能,但请随身携带一份 Dyalog APL 程序员指南和语言参考,因为它是关于该语言的最全面的参考之一。

聚会迟到了,但这里有一个干净的解决方案,对 gnu-apl 是安全的,不使用幂运算符,并且稍微调整了 Lobachevsky 的 "neg-two take" 方法:

fib ← {{⍵, +/ ¯2↑ ⍵} / ⌽ ⍳⍵}

基本技巧是反转 iota 列表,因为压缩会向后读取它。示例输出:

      fib 10
 1 1 2 3 5 8 13 21 34 55