This and other RFCs are available on the web at
http://dev.perl.org/rfc/
=head1 TITLE
Higher order functions
=head1 VERSION
Maintainer: Damian Conway [EMAIL PROTECTED]
Date: 4 August 2000
Version: 2
Mailing List: [EMAIL PROTECTED]
Number: 23
=head1 ABSTRACT
This RFC proposes some syntactic sugar to simplify the creation of
higher-order functions (a.k.a. "currying").
=head1 DESCRIPTION
One situation in which the proposed Perl Cswitch statement does not
provide a good substitute for a cascaded Cif, is where a switch value
needs to be tested against a series of conditions. For example:
sub beverage {
switch (shift) {
case sub{ $_[0] 10 } { return 'milk' }
case sub{ $_[0] 20 } { return 'coke' }
case sub{ $_[0] 30 } { return 'beer' }
case sub{ $_[0] 40 } { return 'wine' }
case sub{ $_[0] 50 } { return 'malt' }
case sub{ $_[0] 60 } { return 'Moet' }
else{ return 'milk' }
}
}
The need to specify each condition as an anonymous subroutine is tiresome.
Each of these small subroutines is really a "higher order" function, which
exists merely to bind the second operand of the
CElt operator.
=head2 The anonymous placeholder
It is proposed that Perl reserve the bareword C^_ (caret-underscore) as
a "placeholder" for generating higher order functions more cleanly.
That is, any expression containing C^_ anywhere that a value might
appear, will be converted to "deferred expression": a reference to a
subroutine in which the placeholders are replaced by the appropriate
number and sequence of arguments.
That is, the expression:
$check = ^_ == ^_**2 *^_ or die ^_;
is equivalent to:
$check = sub (;) {
$_[0] == $_[1]**2 *$_[2] or die $_[3]
};
This could then be invoked:
$check-(@args);
It would also be possible to interpolate an argument list into a static
expression like so:
(^_ == ^_**2 *^_ or die ^_)-(@args);
=head2 Named placeholders
Those not currently studying or using geometry might not be too sure what
they're dealing with when they see:
$check = ^_ == ^_**2 *^_ or die ^_;
in a program. However, the following is self-documenting:
$check = ^cylinder_vol == ^radius**2 * ^height
or die ^last_words;
This uses the Inamed placeholder notation. If two placeholders use the
same identifier, they refer to the same argument. Therefore, the following
is equivalent to the previous line:
$check = ^cylinder_vol == ^radius*^radius * ^height
or die ^last_words;
=head2 Positional placeholders
The order in which the arguments appear in a function may not be
convenient:
# getMeasurements returns ($height, $radius)
@measurements = getMeasurementsFromSomeplace();
$check-($volume, reverse(@measurements), 'Invalid measurements');
A convenient way around this is using Ipositional placeholders:
$check = ^3 == ^1**2 * ^2 or die ^4;
@measurements = getMeasurementsFromSomeplace();
$check-(@measurements, $volume, 'Invalid measurements');
Positional placeholders can be used to re-order named placeholders too:
$check = ^cylinder_vol == ^radius**2 * ^height
or die ^last_words;
$check2 = $check-(^3, ^1, ^2, ^4);
=head2 Combining placeholder types
Although not necessarily a good idea, these can be mixed in a single
higher-order function:
$icky_func = ^test ? ^2 * ^_ : ^3 * ^_;
First the positional placeholders are filled in (a higher numbered
positional placeholder than the number of parameters results in a
compile-time error). The anonymous and named placeholders fill in the
missing places in the order in which they appear, from left to right.
However, for the good of international mental health, users should be
encouraged to consider using a consistent approach within a single
higher-order function definition.
=head2 Examples:
With C^_, the previous ugly case statements can be rewritten:
sub beverage {
switch (shift) {
case ^_ 10 { return 'milk' }
case ^_ 20 { return 'coke' }
case ^_ 30 { return 'beer' }
case ^_ 40 { return 'wine' }
case ^_ 50 { return 'malt' }
case ^_ 60 { return 'Moet' }
else { return 'milk' }
}
}
Likewise a Tree class might provide a traversal callback like so:
$root = Tree-new(load_from = "datafile")
my $sum = 0;
$root-traverse( $sum += ^_ );
Higher order functions would also be very useful with the proposed
Creduce function:
$sum = reduce ^_+^_ (0,@vals);