理解这个 Perl 解决方案

3

我正在尝试解决一个代码高尔夫练习,其中需要输入测试用例的数量,然后每个测试用例的每行输入一个整数。

为了使我的解决方案尽可能地简短,我找到了这个解决方案:

#!perl -lp
use bigint;$_=???<>+1:bnok{2*$_}$_ 

我对perl非常陌生,因此不明白这段代码的实际运作方式。如果有人能帮我解决这个问题,我将不胜感激。

注: 在codegolf.stackexhange上提问并关闭.

1个回答

7

有一些用于解决 Perl golf 的工具。其中一个是 perlsecret,它记录了许多 Perl golf 玩家使用的“秘密操作符”和技巧。

对于这个特定的代码,理解 -p 做什么 也很重要。它将代码包装在一堆其他代码中,可以用于高尔夫比赛。

最后,解开 Perl golf 的终极工具是 B::Deparse。它将 Perl 对代码的理解转换回可读的 Perl 代码,并进行缩进等处理。-p 选项使 B::Deparse 即使不必要也添加括号,这有助于澄清优先级。-d 选项提供了更准确的对象表示。哪些对象?观察即可。

$ perl -MO=Deparse,-p,-d
#!perl -lp
use bigint;$_=???<>+1:bnok{2*$_}$_

Use of ?PATTERN? without explicit operator is deprecated at - line 2.
BEGIN { $/ = "\n"; $\ = "\n"; }
use bigint;
LINE: while (defined(($_ = <ARGV>))) {
    chomp($_);
    BEGIN {
        $^H{'bigint'} = '1';
        $^H{'binary'} = 'CODE(0x7fc88ba3d580)';
        $^H{'float'} = 'CODE(0x7fc88ba3d478)';
        $^H{'integer'} = 'CODE(0x7fc88b298428)';
    }
    ($_ = (?? ? (<ARGV> + bless( {"sign" => "+","value" => [1]}, 'Math::BigInt' )) : (bnok {
        (bless( {"sign" => "+","value" => [2]}, 'Math::BigInt' ) * $_)
    } $_)));
}
continue {
    (print($_) or die("-p destination: $!\n"));
}
- syntax OK

这揭示了一些更加神秘的事情...
  • ???PATTERN?运算符和?:三元运算符的结合,具体来说,??是三元条件语句的条件。
  • ??的工作方式与//相同,但它只匹配一次,直到调用reset。因为在这个程序中没有调用reset,所以它只会匹配一次。而//将匹配任何内容。
  • use bigint将所有整数转换为Math::BigInt对象。
  • bnok是来自Math::BigInt的二项式系数方法。
  • bnok被用作对整数(实际上是Math::BigInt对象)的间接方法调用。间接方法调用的格式为method $object @args,因此bnok{2*$_}$_实际上是(2*$_)->bnok($_),即中心二项式系数
程序的核心内容可以通过一些缩进和垂直空白更容易地理解。拥有良好括号匹配功能的编辑器就足以解决这个问题。
(
    $_ =
      (?? ? (<ARGV> + bless( {"sign" => "+","value" => [1]}, 'Math::BigInt' ))
          : (bnok {(bless( {"sign" => "+","value" => [2]}, 'Math::BigInt' ) * $_) } $_)
      )
);
  • 由于??只会在整个程序中匹配一次,它用于跳过第一行,该行是测试数量。
  • 在第一行之后,??将为false,这将触发bnok计算。

有一个细节我还没有解决。为什么是<>+1而不是<>?它似乎抑制了一个空行,但我不知道为什么。


我已经大大扩展了我的答案,揭示了一个几乎完整的解决方案。 - Schwern
1
我猜+1是为了提供一个标量上下文。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接