When we write code in Imperative programming languages, we make this mistake of considering a procedure as a function many times without realizing it. We keep using word function commonly. Whether the written method is a function or not.
If you do not believe me then keep reading this article and you will see that.
To start with let's see what is actually a Pure Function and Impure Function
Pure Function
The pure function always has following:
- Accepts one or more parameters
- Each parameter belongs to specific domain
- Returns a value or Set of values
Impure functions
If the function which is structured as mentioned above in the definition of the Pure function, but also does some more things like:
- Prints some text on the screen
- Calls CRUD operation on Database table or file etc
- Sends some instruction to a printer to print over the network etc. etc.
Then such functions are referred as Impure functions
and when such code is part of the function, then that causes side-effects to the output of the function.
e.g. if a function sends out an instruction to print the output over the network then it involves external things, which can have side-effects. What if the printer is not connected or some other issue is there. Then it will not respond in an expected manner. If that is the behavior then the function is not a pure function because we can not say it will always return the same response.
That's the reason in Functional Programming we separate the code related to IO, storage etc. from the Pure Function
Now let's check how we confuse our Functions with Procedures.
To explain this we will be writing a program to solve FizzBuzz kind of programming problem.
Program Description:
In this program, we want to show Have Fun At Zoo
text based on the divisible by criteria.
If the number is divisible by 2 then show Have Fun
. If the number is divisible by 7 then show At Zoo
. If number is divisible by 2 and 7 then show Have Fun At Zoo
.
/**
* [printTextBasedOnDisibleBy Function to print the string
* if number is divible by 2 print HAVE FUN
* if number is divible by 7 print AT ZOO
* if number is divible by 2 and 7 print HAVE FUN AT ZOO]
*/
var printTextBasedOnDisibleBy = function() {
var i;
var printval;
for (var i = 1; i <= 100; i++) {
printval = i;
if (i % 7 == 0 && i % 2 == 0)
printval += " Have Fun At Zoo ";
else if (i % 2 == 0)
printval += " Have Fun";
else if (i % 7 == 0)
printval += " At Zoo ";
console.log(printval);
}
}
This looks like a function. However, it is not a function it’s a procedure. Also, It is mixing IO statements as we are printing content in the same function. Moreover, we are not returning anything and we are not taking any input parameters too.
To write a function, we have to do little more and in that process, we will be writing some Pure and Impure functions. So basically we need to do following :
- Separate all the IO operation in the separate function
- Have input parameter to dynamically decide the range for which we want to run this program instead of having hardcoded value up to 100
- Have another input parameters to decide the criteria of divide by 2, 7, 2 and 7 or it may anything
- Have another input parameters to decide the string text for divisible by 2, 7, 2 and 7 or it may anything
- Formatter to format the output string
So lets now rewrite the same code in a functional programming way and let's stop getting confused with procedural and functional way of coding
We are going to re-write the same code in a functional way.
Function to get the default values. It is a pure function.
var doesNotMatch = function(currentNum) {
return [currentNum];
}
Function to check the divisible by criteria. It is a pure function.
var matchesCondition = function(currentTuple) {
numb.map(function(val, i) {
if (currentTuple[0] % val === 0)
currentTuple.push(displayString[i]);
});
return currentTuple;
};
Function to do some manipulations with the result. This is a pure function
var organiseData = function(output) {
var val = "";
output.forEach((item, index) => {
val += `${item} `;
if (index === 0 && output.length > 1) val += " Stands For ";
});
return val;
}
Function to print the final output string. This is an Impure Function as it is handling IO.
var printOrganisedData = function(output) {
console.log(output);
}
Main function. I have used Recursion here to avoid using For Loop. Also in functional programming, we should avoid using For Loop.
var printTextBasedOnDisibleBy = function(startNum, endNum) {
if (startNum === endNum) return;
startNum++;
printTextBasedOnDisibleBy(startNum--, endNum);
defaultFunc = () => doesNotMatch(startNum);
evaluateData = pipe(defaultFunc, matchesCondition);
organisedData = pipe(evaluateData, organiseData);
return pipe(organisedData, printOrganisedData)();
}
This function is a composition function which will take the function as inputs and return a function.
This will also help us make cascade function calls simple and clean. I have named itpipe
as we use pipe|>
operator in Elixir to pass one functions return value to another function and so on. It will work same way
var pipe = function(functionA, functionB) {
return function(arg) {
return functionB(functionA(arg));
}
};
Call to the function
var numb = new Array(2, 7);
var displayString = new Array("Have Fun", "At Zoo");
printTextBasedOnDisibleBy(1, 100);
So now we have six Pure and Impure functions and each function do one thing only. Also, this approach makes our program dynamic too. Now we can give N numbers in the divisible by array and N number of Text and this will serve all.
Happy Programming!! Hope this will help...