Understanding this perl solution

I am trying to solve a golf exercise that involves entering the number of test cases followed by an integer on each line for each test case.

In my quest to get the shortest possible solution, I came across this solution:

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

      

I am very new perl, so I don't understand how this code works. I would appreciate it if anyone can help me figure this out.

PS: Set and closed in codegolf.stackexhange .

+3


source to share


1 answer


There are several tools for learning Perl golf. One perlsecret that documents the "secret operators" and tricks used by many Perl players.

For this particular code, it's also important to understand what -p

it does
. It wraps the code in a bunch of other code, which can then be used to play golf.

Finally, the definitive tool for unpacking Perl golf B :: Deparse . This translates how Perl understood the code back into human-readable indented Perl and the like. The -p option makes B :: Deparse add parentheses even if they are not needed, which may help clarify precedence. The -d option gives a more accurate representation of objects. What objects? Let's notice.

$ 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

      

A few of the more esoteric things it reveals ...



  • ??? it is an operator ?PATTERN?

    plus a ternary operator ?:

    . In particular, it ??

    is a triple condition.
  • ??

    works the same way //

    , but will only match once until called reset

    . Since reset is never called in this program, it will only match once for this program. //

    will match anything.
  • use bigint

    converts all integers to Math :: BigInt objects.
  • bnok

    is the binomial coefficient method from Math :: BigInt .
  • bnok

    used as an indirect method call on integers (which are indeed Math :: BigInt objects). Indirect method calls have the form method $object @args

    , therefore, bnok{2*$_}$_

    in fact (2*$_)->bnok($_)

    , which is the central binomial coefficient .

The meat of the program can be understood a little more easily with some padding and vertical spaces. An editor with a good mix of guys is all you need to get them working.

(
    $_ =
      (?? ? (<ARGV> + bless( {"sign" => "+","value" => [1]}, 'Math::BigInt' ))
          : (bnok {(bless( {"sign" => "+","value" => [2]}, 'Math::BigInt' ) * $_) } $_)
      )
);

      

  • Since ??

    will only match once for the whole program, it skipped the first line, which is the number of tests.
  • After the first line ??

    , it will be false, which will result in the calculation bnok

    .

There is one detail that I have not worked out. Why is this <>+1

, not <>

? It seems to suppress the blank line, but I don't know why.

+7


source







All Articles