You don't need a eval to do this, and it's easier to do without it. You basically want a higher order function that composes other functions, and all of the functions are going to get the same arguments.
Starting from the finished product, you might have a sort subroutine like this, where the return value is the first thing that returns true (which should be -1 or 1).
sub sortsub {
$a cmp $b ||
other_function( $a, $b ) ||
...
}
That's the same as writing it as a collection of subroutines that get arguments instead of using globals though:
sub sortsub {
string_compare( $a, $b ) ||
other_function( $a, $b ) ||
...
}
But I can rewrite that sortsub to take a list of subroutine references as its arguments. Now my sortsub goes through each subroutine and returns when it finds one that returns a true value. If it finds 0 (meaning that sub thought the elements were equal), it goes onto the next subroutine.
sub sortsub {
my @subs = @_;
foreach my $sub ( @subs )
{
my $result = $sub->($a, $b);
return $result if $result;
}
}
I can't use this in sort yet because I can't pass it arguments. I can, however, modify it to return a subroutine reference I can use:
sub make_sort_sub {
my @subs = @_;
return sub {
foreach my $sub ( @subs )
{
my $result = $sub->($a, $b);
return $result if $result;
}
};
}
Now, I basically make the reference then use it in my sort block.
my $sort_sub = make_sort_sub( @sub_references );
my @sorted = sort { $sort_sub->() } @stuff;
And here's a full demo, using it with numbers, then strings, then a user-defined sort subroutine. I don't need an eval for any of it.
#!/usr/bin/perl
# pre-defined common sort subroutines
my %Subs = (
numeric_descending => sub { $b <=> $a },
numeric_ascending => sub { $a <=> $b },
string_descending => sub { $b cmp $a },
string_ascending => sub { $b cmp $a },
case_insensitive => sub { "\L$a" cmp "\L$b" },
);
sub make_sort_sub {
my @subs = @_;
return sub {
foreach my $sub ( @subs )
{
my $result = $sub->($a, $b);
return $result if $result;
}
};
}
# numbers
{
my @use_these_subs = map { $Subs{$_} } qw(numeric_descending);
my $sort_sub = make_sort_sub( @use_these_subs );
my @sorted =
sort { $sort_sub->() } qw( 1 10 11 100 2 12 21 3 31 300 4 5 6 66 7
+ 71 );
print "@sorted\n";
}
# strings
{
my @use_these_subs = map { $Subs{$_} } qw(case_insensitive string_asce
+nding);
my $sort_sub = make_sort_sub( @use_these_subs );
my @sorted =
sort { $sort_sub->() } qw( Fred fred FReD Barney barney Betty BETT
+Y );
print "@sorted\n";
}
# strings by length with user defined subroutine
{
my @use_these_subs = ( sub { length $a <=> length $b } );
push @use_these_subs, map { $Subs{$_} } qw(string_ascending);
my $sort_sub = make_sort_sub( @use_these_subs );
my @sorted =
sort { $sort_sub->() } qw( Fred fred FReD Barney barney Betty BETT
+Y );
print "@sorted\n";
}
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.