12.6.4 Another Function Builder: The Functional if
12.6.4 Another Function Builder: The Functional if
It is possible to combine functions in ways other than complementing or composing them. Those who are adept at functional programming, frequently write code that looks like the following.
Program 12.31
$add1 = sub {$_[0] + 1;};
$add3 = sub {$_[0] + 3;};
sub oddP {
if ($_[0] =~ /[13579]$/) {1} else {0}
}
@numbers = (200, 301, 593, 785, 884, 932);
@result = map { if (oddP $_)
{funcallS ($add1, $_)} else {funcallS ($add3, $_)}
} @numbers;
Here, we are map a piece of code on every element of a list. The mapped code checks if a list element is odd, and if so, adds 1 to it, otherwise it adds 3. It returns the resulting list.
We want to make the same call to map in a slightly compact manner.
@result = map { funcallS (fif (\&oddP, $add1, $add3), $_)} @numbers;
This call returns the following.
203 302 594 786 887 935
We do this by writing a function called fif or the functional if function. The code for the fif function is given below.
Program 12.32
sub fif {
my ($ifF, $thenF, $elseF) = @_;
my $fifF = sub {
if (funcallS ($ifF, $_[0])) {funcallS ($thenF, $_[0])}
else {funcallS ($elseF, $_[0])}
};
return $fifF;
}
fif is sent references to three functions, the test function, the function to be applied if the test function returns to true, and the function to be applied if the test function returns false. fif builds an anonymous function, a reference to which is stored in the scalar $fifF. This anonymous function calls the test function on the parameter given in a call to the anonymous function. Depending on the result of the test, the anonymous function calls the proper function on the parameter sent to the anonymous function. Note that the anonymous function is being built inside fif but not called. fif returns a reference to the code of this anonymous function. So, a call to fif such as
fif (\&oddP, $add1, $add3)
actually returns a reference to a function. This function is the anonymous function we talked about in the previous paragraph. When we make a call to this anonymous function, as in,
funcallS (fif (\&oddP, $add1, $add3), $_)
the anonymous function is called with $_ as a parameter. This parameter is available to the anonymous function as the value of its own $_[0]. The anonymous function now calls the appropriate function depending on the test of the if statement. Finally, when we map this anonymous function using the map function, as in,
map { funcallS (fif (\&oddP, $add1, $add3), $_)} @numbers;
the appropriate function is called on each element of the list numbers.
