I don't know about monads, but one often useful reason for functional programming is deferred execution and simulation modeling. For example, I might need to set up a complex set of calculations at the start of the program. The calculation itself is designed at the start of the program based on user input. The outcome of the model relies on values that we will only know later on in the program.
Here is a rather silly example, implementing a prototype of a child's algebra game. Even though we have only defined two operations (add, multiply), we can generate and solve problems for any polynomial equation the child wants to play with:
Note: the use of %VARIABLES means that this is not "pure" functional programming where parameters alone are the only influence on a function's outcome.
use strict;
use warnings;
#===============================================
# THE GAME PROTOTYPE
#===============================================
my %VARIABLES;
# child picks a kind of problem: Z = (X+Y)^2
# we parse their formula and set up something like this:
my $aVariables = [ 'X', 'Y' ];
my $sEquation = "(X + Y)^2";
my $X = getVar('X');
my $Y = getVar('Y');
my $Z = multiply(add($X,$Y),add($X,$Y));
# now we play a game where we calculate the solution using
# different variable inputs
for (1..5) {
# assign values to variables and print out the problem
# the print out looks something like this:
# "Problem #1: if X=1 and Y=4 and ...., what is X + Y + ... ?"
print "\nproblem $_: If "
. join(' and '
, map { $VARIABLES{$_} = int rand(10) + 1;
"$_=$VARIABLES{$_}"
} @$aVariables)
. ", what is $sEquation ?\n";
print "hey! you got it right: the answer is ";
print "Z = " . &$Z . "\n\n";
}
#===============================================
# THE FUNCTION GENERATORS
#===============================================
sub getVar {
my $x = shift;
return sub { return $VARIABLES{$x}; }
}
sub makeFunc {
my $x = shift;
return ref($x) eq 'CODE'
? $x : sub { return $x; };
}
sub add {
my ($x, $y) = @_;
my $crX = makeFunc($x);
my $crY = makeFunc($y);
return sub {
my $result= &$crX + &$crY;
#print STDOUT "\tevaluating: $x + $y => $result\n";
return $result;
};
}
sub multiply {
my ($x, $y) = @_;
my $crX = makeFunc($x);
my $crY = makeFunc($y);
return sub {
my $result= &$crX * &$crY;
#print STDOUT "\tevaluating: $x*$y => $result\n";
return $result;
}
};
And here's output for a sample run with the calculation process exposed:
problem 1: If X=2 and Y=5, what is (X + Y)^2 ?
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 7
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 7
evaluating: CODE(0x8183650)*CODE(0x8183524) => 49
hey! you got it right: the answer is Z = 49
problem 2: If X=3 and Y=3, what is (X + Y)^2 ?
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 6
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 6
evaluating: CODE(0x8183650)*CODE(0x8183524) => 36
hey! you got it right: the answer is Z = 36
problem 3: If X=5 and Y=3, what is (X + Y)^2 ?
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 8
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 8
evaluating: CODE(0x8183650)*CODE(0x8183524) => 64
hey! you got it right: the answer is Z = 64
problem 4: If X=8 and Y=10, what is (X + Y)^2 ?
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 18
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 18
evaluating: CODE(0x8183650)*CODE(0x8183524) => 324
hey! you got it right: the answer is Z = 324
problem 5: If X=8 and Y=8, what is (X + Y)^2 ?
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 16
evaluating: CODE(0x814ec28) + CODE(0x818a8c0) => 16
evaluating: CODE(0x8183650)*CODE(0x8183524) => 256
hey! you got it right: the answer is Z = 256
A more real-life example might involve something that lets a user define a process flow. We compose the process flow using functions. Then later on we run the user composed process flow against a number of different real life inputs.