Как я могу кодировать в функциональном стиле на Perl? - PullRequest
4 голосов
/ 03 февраля 2010

Как вы можете:

  1. есть sub возврат sub

    или

  2. выполнить текст как код

в Perl?

Кроме того, как мне получить состояние анонимного хранилища функций?

Ответы [ 4 ]

16 голосов
/ 03 февраля 2010

Подставка возвращает подпрограмму как coderef :

# example 1: return a sub that is defined inline.
sub foo
{
    return sub {
        my $this = shift;
        my @other_params = @_;

        do_stuff();
        return $some_value;
    };
}

# example 2: return a sub that is defined elsewhere.
sub bar
{
    return \&foo;
}

Произвольный текст может быть выполнен с помощью функции eval: см. Документацию по адресу perldoc -f eval :

eval q{print "hello world!\n"};

Обратите внимание, что это очень опасно , если вы оцениваете что-то извлеченное из пользовательского ввода, и, как правило, это плохая практика, так как вы можете определить свой код в coderef, как в предыдущих примерах выше. 1014 *

Вы можете сохранить состояние с переменной состояния (новинка в perl5.10) или с переменной, имеющей область действия выше, чем само саб, как замыкание :

use feature 'state';
sub baz
{
    state $x;
    return ++$x;
}

# create a new scope so that $y is not visible to other functions in this package
{
    my $y;
    sub quux
    {
        return ++$y;
    }
}
7 голосов
/ 03 февраля 2010

Возвращает ссылку на подпрограмму.

Вот простой пример, который создает подчиненные ссылки, закрытые по значению:

my $add_5_to = add_x_to(5);

print $add_5_to->(7), "\n";

sub add_x_to {
    my $x = shift;

   return sub { my $value = shift; return $x + $value; };

}

Вы также можете работать с именованными подпрограммами следующим образом:

sub op {
    my $name = shift;

    return $op eq 'add' ? \&add : sub {};
}

sub add {
    my $l = shift;
    my $r = shift;

    return $l + $r; 
}

Вы можете использовать eval с произвольной строкой, но не делайте этого. Код трудно читать, и он перезапускает компиляцию, что замедляет все. Есть небольшое количество случаев, когда строка Eval является лучшим инструментом для работы. Каждый раз, когда строка eval кажется хорошей идеей, вам, скорее всего, лучше использовать другой подход.

Практически все, что вы хотели бы сделать со строкой eval, можно достичь с помощью замыканий.

5 голосов
/ 03 февраля 2010

Вы можете создавать анонимные подпрограммы и получать к ним доступ по ссылке;эта ссылка, конечно, может быть присвоена скаляру:

my $subref = sub { ... code ... }

или возвращена из другой подпрограммы

return sub { ... code ... }

Если вам нужно сохранить состояния, вы можете создавать замыкания с лексическими переменными, определеннымивнешняя область видимости:

sub create_func {
    my $state;
    return sub { ... code that can refer to $state ... }
}

Вы можете запустить код с помощью eval

5 голосов
/ 03 февраля 2010

Вернуть сабы легко, используя ключевое слово sub.Возвращенная подпрограмма закрывается по используемым лексическим переменным:

#!/usr/bin/perl

use strict; use warnings;

sub mk_count_from_to {
    my ($from, $to) = @_;
    return sub {
        return if $from > $to;
        return $from ++;
    };
}

my $c = mk_count_from_to(-5, 5);

while ( defined( my $n = $c->() ) ) {
    print "$n\n";
}

5.10 введено переменные состояния .

Выполнение текста как Perl выполняется с использованием eval EXPR:

возвращаемое значение EXPR анализируется и выполняется, как если бы это была небольшая Perl-программа.Значение выражения (которое само определяется в скалярном контексте) сначала анализируется, и, если не было никаких ошибок, выполняется в лексическом контексте текущей программы Perl, так что любые настройки переменных или определения подпрограммы и формата остаются впоследствии,Обратите внимание, что значение анализируется каждый раз, когда eval выполняет

Выполнение произвольных строк откроет огромные дыры в безопасности.

...