Why Functional Programming?
The central problem of programming is managing complexity. So, writing clean, error-free and robust code is key to software projects’ success.
Functional programming is a paradigm designed with software reliability, clarity, readability and robustness as the main goals. It is a declarative programming style where we use only functions and expressions to tell the computer what to do – we do not explicitly state how to do it. Also, it has a set of principles and restrictions that improve code quality and reduce bugs.
Pure Functions vs Impure Functions
A function must meet two conditions to be a pure function.
- It must produce the same output for the same input. The global state or other functions/objects should not alter its output.
- It should not have any side effects in the outside world
Example of a Pure Function
This is a pure function as it gives the same output for the same inputs and does not affect any variable outside itself.
Example of Impure Function
This is an impure function because the output changes if the global variable “name” changes.
Example of Impure Function 2
This is another impure function as it has a side effect – it changes the value of the global variable “outsideVar”.
Functional Programming Principles
The functional programming paradigm provides a set of principles to follow to write clean, clear and maintainable code.
1) Use only Pure Functions
We saw impure functions have side effects and take external inputs. Both these factors can create confusion and bugs in the code. What is the current value of the external input variable? Did I miss any side effects?
Two other benefits of using only pure functions are:
- Parallelism – We can speed up processing by executing pure functions in parallel as they do not depend on outside inputs and do not affect the outside world. So, there is no risk of two simultaneous function calls causing conflicts.
- Memoization – We can cache the output from pure functions for different inputs to speed up execution as pure functions produce the same output for the same inputs.
2) Do not mutate data
Mutating data in place is the cause of many bugs. Therefore, functional programming explicitly prohibits it and instead asks us to store the returned values after operations in new variables.
3) Use function expressions and declarations instead of statements
This helps us use other powerful features of functional programming like closures and higher-order functions (more on them later).
Also, the new const declaration lets us declare immutable data, one of the core functional programming principles.
Map is an array method that operates on each element of an array but stores the returned values in a new array.
The callback function operates on each item of the array. Map then returns a new array that stores the returned values from the callback.
The callback_reducer takes an accumulator value and the current value and operates on them to store the returned value as the new accumulated value.
Concat adds elements to an array, but it creates a new array. This makes it a pure function, unlike the push() method, which mutates the original array in place.
4) Our Own Pure Function
5) Higher-order Functions
Higher-order functions can accept other functions as arguments and return functions. Higher-order functions let us create powerful, reusable functions to use the full power of functional programming.
The negation function “negFunc" is a higher-order function that negates whatever function we pass to it. It is a powerful tool to apply to any function to quickly "invert" it.
6) Currying into Multiple Higher-Order Functions
Currying is the technique to break down a function into several higher-order functions. Currying lets us memoize costly operations in function argument calls to retrieve their values from the cache and speed up processing.
Here we break down the comparer function into multiple higher-order functions. This helps us memorize the costly array sum operation and compare it with different values by using its cached value.
We can feed the output of one function as the input to another function to create a chain of functions. Also, we can extend this composition to any number of pure functions. Chaining lets us write complex operations in a single crisp, functional code line.
What are the advantages of functional programming?
Functional programming helps us write clean and maintainable code. Please read our post above for a deep dive into the many benefits of functional programming.
What other languages support functional programming?