简体   繁体   中英

How can I code in a functional style in Perl?

How do you either:

  1. have a sub return a sub

    or

  2. execute text as code

in Perl?

Also, how do I have an anonymous function store state?

A sub returns a sub as a 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;
}

Arbitrary text can be executed with the eval function: see the documentation at perldoc -f eval :

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

Note that this is very dangerous if you are evaluating anything extracted from user input, and is generally a poor practice anyway as you can generally define your code in a coderef as in the earlier examples above.

You can store state with a state variable (new in perl5.10), or with a variable scoped higher than the sub itself, as a closure :

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;
    }
}

Return a subroutine reference.

Here's a simple example that creates sub refs closed over a value:

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; };

}

You can also work with named subs like this:

sub op {
    my $name = shift;

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

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

    return $l + $r; 
}

You can use eval with an arbitrary string, but don't do it. The code is hard to read and it restarts compilation, which slows everything down. There are a small number of cases where string eval is the best tool for the job. Any time string eval seems like a good idea, you are almost certainly better off with another approach.

Almost anything you would like to do with string eval can be achieved with closures.

Returning subs is easy by using the sub keyword. The returned sub closes over the lexical variables it uses:

#!/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 introduced state variables .

Executing text as Perl is accomplished using eval EXPR :

the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar context) is first parsed, and if there weren't any errors, executed in the lexical context of the current Perl program, so that any variable settings or subroutine and format definitions remain afterwards. Note that the value is parsed every time the eval executes

Executing arbitrary strings will open up huge gaping security holes.

You can create anonymous subroutines and access them via a reference; this reference can of course be assigned to a scalar:

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

or returned from another subroutine

return sub { ... code ... }

If you need to store states, you can create closures with lexical variables defined in an outer scope like:

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

You can run code with eval

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM