🎄 15/25. 在 Perl 6 中使用斐波那契数

欢迎来到 Perl 6 One-Liner Advent Calendar 的第15天!今天,将有两个单行程序,它们都产生斐波纳契数

是的,最有可能的是,你从未在实际代码中使用过这样的数字,而且,很可能,你用它们解决了许多教育问题。然而,今天,让我们解决欧拉项目的问题25,并尝试在 Code-Golf.io 站点上寻找最短的 Fibonacci 问题解决方案。

Pre-party

我们如何在 Perl 6 中形成 Fibonacci 序列呢?使用序列运算符 ...:

1
0, 1, * + * ... *

如果你想在代码中有一些奇特的味道,你可以用 Inf 替换最后的那个星号。在任何情况下,结果都是 Seq 类型的惰性序列。 Perl 6 不会立即计算它(并且它不能,因为右边缘是无限的)。

第1部分

第一个任务是找到第一个 Fibonacci 数的索引,该数字有 1000 个数字。当然,你可以循环上面创建的序列并自己跟踪索引。但是在 Perl 6 中,有一个选项可以修改 grep 例程簇,并要求它返回匹配项的索引而不是项本​​身。

另外,我们将使用更合适的方法 first 代替 grep。如果我们用 k 键调用该方法,它将返回第一个匹配项或其索引。仅仅提到键就足够了,真的不需要值。

1
say (0, 1, * + * ... *).first(*.chars >= 1000, :k)

该程序打印一个整数,这是给定问题的正确答案。

第2部分

现在让我们解决一个高尔夫任务并打印前30个斐波那契数字,用单行程序。这次,我们必须在代码中使用尽可能少的字符。

第一种方法相当冗长(即使使用 ^31 代替 0..30,它需要 33 个字符):

1
.say for (0, 1, * + * ... *)[^31]

可以压缩一些空间。当然,第一个也是最明显的就是删除空格(剩下28个字符):

1
.say for (0,1,*+*...*)[^31]

另一个有趣的技巧是使用 >> meta-operator 在序列的每个元素上调用 say 方法。它将代码进一步压缩为24个字符:

1
(0,1,*+*...*)[^31]>>.say

此时,我们可以使用一些 Unicode,并节省三个以上的字符(左21):

1
(0,1,*+*…*)[^31]».say

看起来已经够紧凑了,但仍有一些选项可供尝试。让我们摆脱显式切片,并尝试在最后一个元素处停止序列:

1
(0,1,*+*…*>514229)».say

代码变得更长(23个字符),但我们这里不需要确切的数字 514229。给出一些数字就足够了,这个数字比第29个更大,然后小于序列的第30个元素。例如,它可以是 823543,它是7的7次幂。使用上标(19个字符)来写:

1
(0,1,*+*…*>7⁷)».say

最后,通过在单个字符中使用另一个代表 800000 的 Unicode 字符,可以减少一个字符。并非每个(如果有的话)字体都能显示出具有视觉吸引力的东西,但 Perl 6 能识别该字符:

1
(0,1,*+*…*>𐧴)».say

18个字符Gode-Golf的第一名多一个字符。我有一种感觉,你可以通过用 ^2 替换序列的前两个元素来节省另一个字符,但这在当前的Rakudo中不起作用,你必须多用一个字符来展平列表:|^2,这使得答案再次变成18个字符。

希望删除条件中的 *> 部分以停止序列并用固定数字替换它。不幸的是,没有办法用1到90之间的数字的幂来表示 832040。这是可能的,我们可以使用上标来计算数字。

另一个想法是使用正则表达式,但我们需要至少四个字符,这没有帮助:

1
(0,1,*+*…/20/)».say

让我今天到此为止。你是否碰巧创建了一个更短的答案,请在下方评论。明天见!