2014-11-07 2 views
3

Я пытаюсь решить упражнение для игры в гольф, которое включает в себя ввод количества тестов, за которым следует целое число в каждой строке для каждого тестового примера.Понимание этого решения perl

В своем стремлении получить кратчайшее решение, которое я наткнулся на this решения:

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

Я очень новый Perl, поэтому я не получаю, как этот код на самом деле работает. Буду признателен, если кто-нибудь поможет мне понять это.

PS: Asked and closed at codegolf.stackexhange.

ответ

7

Существует несколько инструментов для изучения гольфа Perl. Один из них - perlsecret, который документирует «секретные операторы» и трюки, используемые многими игроками в Perl.

Для этого конкретного кода также важно понять, что такое -p does. Он обертывает код в кучу другого кода, который затем можно использовать для игры в гольф.

Наконец, конечным инструментом для распаковки гольф-полей Perl является 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. Поскольку сброс никогда не вызывается в этой программе, он будет соответствовать только один раз для этой программы. // будет соответствовать чему угодно.
  • use bigint превращает все целые числа в объекты Math :: BigInt.
  • bnok - метод биномиального коэффициента от Math::BigInt.
  • bnok используется как косвенный вызов метода для целых чисел (которые действительно являются объектами Math :: BigInt). Косвенные вызовы методов имеют вид method $object @args, поэтому bnok{2*$_}$_ - это фактически (2*$_)->bnok($_), который является central binomial coefficient.

Мясо программы может быть понято немного легче с некоторыми углублениями и вертикальными пробелами. Редактор с хорошим сочетанием парнов - это все, что вам нужно для их работы.

(
    $_ = 
     (?? ? (<ARGV> + bless({"sign" => "+","value" => [1]}, 'Math::BigInt')) 
      : (bnok {(bless({"sign" => "+","value" => [2]}, 'Math::BigInt') * $_) } $_) 
    ) 
); 
  • Поскольку ?? будет соответствовать только один раз для всей программы, она используется, чтобы пропустить первую строку, которая является количество тестов.
  • После первой строки ?? будет ложным, что вызовет расчет bnok.

Есть одна деталь, которую я не разработал. Почему это <>+1, а не <>? Кажется, он подавляет пустую строку, но я не знаю почему.

+0

Я значительно расширил свой ответ, чтобы выявить почти полное решение. – Schwern

+1

Я полагаю, что +1 предназначен для обеспечения скалярного контекста. – tripleee

Смежные вопросы