I'm a big fan of functional programming, so when I discovered block references in Perl I started using them a lot.
However, the functions I've written that take blocks as arguments are written in this style:
sub mygrep (&@) {
my $code = shift;
my @result;
foreach $_ (@_) {
push(@result, $_) if &$code;
}
@result;
}
(From http://perldoc.perl.org/perlsub.html#Prototypes)
In essence, most of my functions set $_
in order for the code block to gain access to data in my sub. I guess my question can be split into three subquestions:
local
ize $_
before setting it? I'm still a Perl newbie so any answers and suggestions are appreciated - thanks in advance! :)
In the code you have written:
sub mygrep (&@) {
my $code = shift;
my @result;
foreach $_ (@_) {
push(@result, $_) if &$code;
}
@result;
}
The foreach
loop is implicitly localizing the $_
variable on every loop iteration. It is perfectly safe (and the fastest way to get values into $_
properly).
The only nit that I have with the code above is that every time &$code
is executed, it has access to the source argument list, which could cause a bug. You could rewrite the code as follows:
sub mygrep (&@) {
my $code = shift;
my @result;
foreach $_ (splice @_) {
push(@result, $_) if &$code; # @_ is empty here
}
@result;
}
Here are a few other ways you could write that function:
sub mygrep (&@) {
my ($code, @result) = shift;
&$code and push @result, $_ for splice @_;
@result
}
sub mygrep (&@) {
my $code = shift;
# or using grep in our new grep:
grep &$code, splice @_
}
Each of these examples provides an aliased $_
to its subroutine, with proper localization.
If you are interested in higher order functions, I'd encourage you to take a look at my module List::Gen on CPAN, which provides dozens of higher order functions for manipulating both real and lazy lists.
use List::Gen;
my $list = filter {$_ % 2} <1..>;
# as a lazy array:
say "@$list[0 .. 5]"; # 1 3 5 7 9 11
# as an object:
$list->map('**2')->drop(100)->say(5); # 40401 41209 42025 42849 43681
zip('.' => <a..>, <1..>)->say(5); # a1 b2 c3 d4 e5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With