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";
}
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
Outside of code tags, you may need to use entities for some characters:
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.