If you have a functional background you cannot live without your map and
filter. They are elegant, they are simple, they are one of the things
which IMHO Java misses more.
Perl has got map and grep, the second being essentially a filter
(the name comes definitely from the Unix shell world). You start using
them, and eventually you want to do your own function accepting a block.
How can you do that?
The perlsub document gives you an answer: you can use Function prototypes. They allow you to override the default parameter expansion of Perl. And if you do it in a sensible way, you can make people very happy, including yourself.
So, it turns out that the & symbol allows a block to be passed as actual
parameter, having a code reference on the other side. Totally sweet. I
especially loved the crazy try-catch definition (but I'll let you seek
for it, your head will explode :D)
So far so good, I created my own reduce, which is kind of improper, as
not really implemented as recursive call...
#!/usr/bin/perl -w
use strict;
use warnings;
use feature qw(say);
sub reduce (&@) {
my $f = shift;
my $acc;
for my $x (@_) {
if (defined $acc) {
$acc = $f->($acc, $x);
} else {
$acc = $x;
}
}
$acc;
}
my @a = (1, 2, 3, 4);
my $sum = reduce { $_[0] + $_[1] } @a;
say $sum;
Guess what, we've got 10 as expected. But, but, but... that $_[0] and
$_[1] thing is not so perlish. To obviate we can define the two
special package variables $a and $b, as people expect while using the
sort function.
You see, this is a nice use case for the local keyword, which enables as
safe and nice dynamic binding of the two variables. You don't have
actual parameters, and you don't need global variables.
#!/usr/bin/perl -w
use strict;
use warnings;
use feature qw(say);
sub reduce (&@) {
my $f = shift;
my $acc;
for my $x (@_) {
if (defined $acc) {
local ($a, $b) = ($acc, $x);
$acc = &$f;
} else {
$acc = $x;
}
}
$acc;
}
my @a = (1, 2, 3, 4);
my $sum = reduce { $a + $b } @a;
say $sum;
Run that... 10 again. Perl is so funny.