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.