Какие функции времени компиляции предоставляет Perl, чего нет в других языках? - PullRequest
4 голосов
/ 26 августа 2010

Является ли Perl универсальным языком программирования?

Чтение об этом в Википедии

Perl имеет полную по Тьюрингу грамматику, потому что на синтаксический анализ может влиять код времени выполнения, выполняемый на этапе компиляции. [41] Следовательно, Perl не может быть проанализирован прямой комбинацией лексера / синтаксического анализатора Lex / Yacc. Вместо этого интерпретатор реализует свой собственный лексер, который координируется с модифицированным синтаксическим анализатором бизонов GNU для устранения неоднозначностей в языке.

Часто говорят, что "только Perl может анализировать Perl", что означает, что только интерпретатор Perl (perl) может анализировать язык Perl (Perl), но даже это, в общем-то, неверно. Поскольку интерпретатор Perl может моделировать машину Тьюринга во время фазы компиляции, он должен решить проблему остановки, чтобы выполнить синтаксический анализ в каждом случае. Это давний результат того, что проблема остановки неразрешима, и поэтому даже Perl не всегда может проанализировать Perl. Perl делает необычный выбор, предоставляя пользователю доступ ко всем возможностям программирования на этапе компиляции. Стоимость с точки зрения теоретической чистоты высока, но практические неудобства кажутся редкими.

Итак, в нем говорится, что, хотя Perl имеет значок завершения Тьюринга, он отличается от других языков, поскольку предоставляет «пользователю доступ ко всем возможностям программирования на его собственной фазе компиляции». Что это значит? Какие возможности программирования Perl предоставляет мне на этапе компиляции, чего нет у других?

Ответы [ 3 ]

6 голосов
/ 26 августа 2010

Нет никаких возможностей Perl, которые не отображаются ни на одном другом языке.Lisp может делать все что угодно (здесь приведен пример ).Поэтому, возможно, мы сможем сузить вопрос до того, каковы особенности Perl, делающие широкие колебания поведения легким делом.

  • BEGIN блоков (также END-блоков), которые изменяют поведение во время компиляции.Поэтому я могу написать Perl-код, который меняет расположение загружаемых модулей.

    Даже следующий код может иметь другое значение.

    use Frobnify;
    Frobnify->new->initialize;
    

    Потому что я мог бы изменить, откуда Frobnify загружает:

    BEGIN { 
        if ( [ localtime ]->[6] == 2 ) { 
            s|^/var|/var/days/tuesday| foreach @INC;
        }
    }
    

    Поэтому по вторникам я загружаю /var/days/tuesday/perl/lib/Frobnify.pm

  • Исходные фильтры может программно редактировать код, который будет выполнять.(CAVEAT на исходных фильтрах!) (Грубо и примерно эквивалентно макросам LISP)

  • В некоторой степени вместе с BEGIN блоками являются @INC ловушки .Как я могу изменить @INC в начале, чтобы увидеть изменения, что загружается.Я могу установить подпрограмму в начале массива @INC для загрузки всего, что я хочу загрузить.Хук может получить запрос на загрузку Frobnify и ответить на него, загрузив Defrobnify.pm.

  • В некоторой степени это символьная манипуляция.После загрузки Defrobnify.pm я могу сделать следующее:

    *Frobnify:: = \*Defrobnify::;
    

    Теперь Frobnify->new создает Defrobnify объект!

4 голосов
/ 26 августа 2010

Прототипы подпрограмм - это функция времени компиляции, более или менее эксклюзивная для Perl. Многие встроенные функции Perl навязывают свои аргументы специальным типам контекста (скаляр, список, ссылка, кодовый блок, захват). Прототипы - это способ перенести некоторые из этих функций в пользовательские подпрограммы.

Например, Perl позволяет эффективно генерировать новые синтаксические конструкции с прототипом (&). Это используется в таких модулях, как Try :: Tiny для добавления try и catch ключевых слов к языку:

    try {
            die "foo";
    } catch {
            warn "caught error: $_"; # not $@
    };

Это работает, потому что try и catch объявлены как sub try (&;@) { ... }. Синтаксис sub name {...} эквивалентен BEGIN { *name = sub {...} }, что означает, что он имеет эффект времени компиляции. В случае try прототип (&;@) сообщает компилятору, что каждый раз, когда он видит идентификатор try, первый аргумент должен быть пустым блоком, а следующий за блоком является необязательным списком.

Это всего лишь один пример прототипов, и они могут делать много других вещей:

$  imposes scalar context on an argument
&  imposes code context on an argument
@  imposes list context on an argument
%  imposes list context (with an even number of elements)
*  imposes glob context on the argument 
\$ imposes scalar reference context
\@ imposes array reference context
   ... for the rest of the sigils

Из-за своей мощи (и отсутствия в других языках) прототипы могут сбивать с толку и лучше всего их использовать при модерации. (как и любая другая расширенная функция Perl).

1 голос
/ 26 августа 2010

Простой ответ состоит в том, что BEGIN блоки обеспечивают полноту по Тьюрингу:

BEGIN {
    my $foo = turing_machine_simulator($program);
}

BEGIN блоки выполняются, как только компилятор Perl их видит. Это означает, что компилятору может быть предложено выполнять задачи произвольной сложности. Все, что может сделать Perl, он может сделать на этапе компиляции.

...