Reputation: 15917
Is there any way to achieve partial application in Perl?
Suppose, I want to do something like:
sub each_file($arr, $op) {
$op->($_) for @{$arr};
...
}
sub each_line($op, $file) {
...
}
each_file($arr, each_line($op));
I want to partially apply each_line()
to only $op
, so it'll become a new function can be passed to $each_file
, how do I express this in idiomatic Perl?
Upvotes: 2
Views: 487
Reputation: 1697
You can roll this functionality up into a class. Then you can overload the subroutine dereference operator to make it look like your class is really a code reference.
package Partial;
use overload '&{}' => \&call;
sub new {
my $class = shift;
my $code = shift;
bless {code => $code, args => \@_}, $class;
}
sub call {
my ($self) = @_;
return sub{ $self->{code}->(@{$self->{args}}, @_) }
}
You can then use it like this:
sub printArgs {
print join ", ", @_;
print "\n";
}
my $partial = Partial->new(\&printArgs, 'foo', 'bar');
$partial->('baz', 'bat');
# prints foo, bar, baz, bat
Upvotes: 0
Reputation: 27207
You can do this in Perl with two approaches combined:
A function which returns a function reference
Closures
Example:
sub each_file {
my ($arr, $line_fn) = @_;
$line_fn->($_) for @{$arr};
...
}
sub each_line {
my ($op, $file) = @_;
...
}
sub make_line_processor {
my ( $op ) = @_;
# This is closed over $op, which effectively becomes
# a constant for the returned function
my $fn = sub {
return each_line( $op, @_ );
};
return $fn;
}
# To call it:
each_file( $arr, make_line_processor($op) );
This can be an even more useful technique in cases where you don't want $op
directly, but some expensive-to-fetch derivation of it. In which case you would calculate the derived value just once (in the make_line_processor
function) and close over that instead.
Upvotes: 2
Reputation: 15264
# given some $op as implied by your code snippet
each_file($arr, sub { each_line($op, shift) });
# shift op will be applied when anonymous sub { … } is called
(Your code snippet doesn't make it entirely clear what you intend $op
to be when you make the call to each_line
. It's usually better to present small working programs.)
Upvotes: 1