# Benefits of Functional Programming by Example

--

Functional programming is a programming paradigm (technique) where functions are used together to return new values, rather than modifying variable values multiple times. Functions that always return the same result given the same inputs are said to be free of side effects, or pure. When code relies on changes to external variables, it can lose its purity because the same inputs no longer create the same outputs consistently. By finding purer ways to design programs, we can use functions in ways that won’t impact how other code works through side effects. This functional approach to programming often leads to more reusable, testable, and stable code.

Functional programming can be difficult to understand at first, especially due to its complex terminology. Rather than learning more theoretical aspects of functional programming, we’ll look at some examples of how to improve existing JavaScript code using functional programming (though these concepts can be applied to most languages).

## Iterating with forEach

`for`

loops are commonly used to iterate over collections in many languages including JavaScript. Let’s say we have an array of values we need to display in alerts individually.

`const beatles = ['John', 'Paul', 'George', 'Ringo']`

for (const beatle of beatles) {

alert(beatle)

}

This example can be simplified further with a newer JavaScript function called `forEach`

.

`const beatles = ['John', 'Paul', 'George', 'Ringo']`

beatles.forEach(beatle => alert(beatle))

Using `forEach`

we can pass a function called an iteratee, which is called with each value of the array, giving us the same result. `forEach`

is called a high order function because it takes a function as an argument. This is a powerful functional programming technique for composing functionality with small, simple functions. Because `alert`

is a function and functions are also values in JavaScript, we can refer to the existing `alert`

function instead of wrapping it in a new function.

`const beatles = ['John', 'Paul', 'George', 'Ringo']`

beatles.forEach(alert)

## Creating new arrays with map

One of the most common use cases for iterating over an array is modifying each item of the array in place. For example, let’s take an array of numbers and round them individually. We will also need to keep track of the current array index.

`const numbers = [1.4, 2.6, 3.14]`

let index = 0

for (const number of numbers) {

numbers[index] = Math.round(number)

index++

}

numbers // [1, 3, 3]

`numbers`

is in the preferred format, but what if we’re only formatting numbers to make them easier to read, and we still need the decimal places for precise calculations? We’ve lost precision of our numbers, and any math code relying on the same array may have less accurate results. This is an unwanted side effect of rounding `numbers`

in a `for`

loop. Instead, we can take a more functional approach and create a new array instead of modifying the values in the original array, preventing subtle bugs and promoting reuse.

`const numbers = [1.4, 2.6, 3.14]`

const rounded = []

for (const number of numbers) {

rounded.push(Math.round(number))

}

rounded // [1, 3, 3]

This is safer, but the nature of `for`

loops still requires the side effect of pushing to the new rounded array. What if we could iterate over the array like with `forEach`

, but create a new array by applying `Math.round`

to every value? Fortunately, there’s a similar function called `map`

which returns a new array based on the return values of the given function.

`const numbers = [1.4, 2.6, 3.14]`

const rounded = numbers.map(Math.round) // [1, 3, 3]

This gives us the result we want without modifying a temporary array variable. We could even replace `Math.round`

with a different pure function, and the original `numbers`

would remain the same. These functional changes have added a lot of safety and reusability to our code, without requiring us to write in a different functional programming language.

## Creating new values with reduce

The `map`

function is handy for updating array values individually, but we often need to calculate a value that isn’t an array of the same length as the original. For example, let’s add numbers in an array together.

`let sum = 0`

const numbers = [1, 2, 3, 4]

numbers.forEach(number => sum += number)

sum // 10

We need to modify our `sum`

here to add each `number`

to it, but there’s a more pure way to combine these values without creating side effects in a temporary `sum`

variable. Like the functions we’ve tried so far, `reduce`

iterates over each value of an array, except it lets us build any new value (not just an array) one step at a time. The reduce function works by passing a special value called an accumulator along with each value of the original array, which is replaced by the return value of our given function after iterating over each value.

`const numbers = [1, 2, 3, 4]`

const sum = numbers.reduce((accumulator, number) => accumulator + number) // 10

We can combine our numbers into a new `accumulator`

value individually, without modifying the original array of numbers. Here our iteratee function is called a reducer because it takes two values (the previous `accumulator`

and the current `number`

) and reduces (combines) them into a single value, our new `sum`

. The initial value of `accumulator`

defaults to the first array value (1 in this case), so `reduce`

will add each number in sequence to `accumulator`

until we reach our final result. This initial value makes sense for a sum, but sometimes we need to change the initial value too. Let’s build a new array by doubling each of its numbers.

`const numbers = [1, 2, 3, 4]`

const doubled = numbers.reduce((accumulator, number) => accumulator.concat(number * 2), []) // [2, 4, 6, 8]

Along with our reducer function, we also pass add a second argument which overrides the initial `accumulator`

to an empty array (instead of the first item, 1). This is necessary because you can’t call `concat`

on a number, so we need to wrap the first number in an array like all the others. This end result is similar to `map`

, which we just reimplemented ourselves by concatenating each `number`

one at a time. `map`

is an example of a function that can be replaced with `reduce`

, but functional code is often easier to read with `map`

.

`const numbers = [1, 2, 3, 4]`

const doubled = numbers.map(number => number * 2) // [2, 4, 6, 8]

## Filtering arrays with filter

Let’s write a reducer that concatenates only even numbers into a new array.

`const numbers = [1, 2, 3, 4]`

const isEven = number => number % 2 === 0

const even = numbers.reduce((accumulator, number) => isEven(number) ? accumulator.concat(number) : accumulator, []) // [2, 4]

As powerful as `reduce`

is, there are other simplified high order functions besides `map`

. The `filter`

function also iterates over array values, but instead of returning a new `accumulator`

for each value, it only concatenates values into the new array if a certain condition is truthy. Let’s use `filter`

to get even numbers from our array using our `isEven`

function. `isEven`

is an example of a predicate, a function that takes a value and returns a boolean.

`const numbers = [1, 2, 3, 4]`

const isEven = number => number % 2 === 0

const even = numbers.filter(isEven) // [2, 4]

## Testing conditions with some and every

Sometimes we want to use predicates to test the values in existing arrays, without creating new arrays. `some`

and `every`

also take predicates, but they return true if our predicate is true for some (any) or every (all) values of the array respectively.

`const numbers = [1, 2, 3, 4]`

const isEven = number => number % 2 === 0

const someEven = numbers.some(isEven) // true

const everyEven = numbers.every(isEven) // false

We could alternatively use a `for`

loop with new variables or even `reduce`

, but these simpler functions clarify the intent of our code while avoiding the side effects of a `for`

loop.

## Function composition

Sometimes a more complex reducer can be simplified by calling multiple pure high order functions together. Let’s combine some of the concepts we reviewed and square all the even numbers in our array.

`const numbers = [1, 2, 3, 4]`

const isEven = number => number % 2 === 0

const square = number => Math.pow(number, 2)

const evenSquared = numbers.reduce((accumulator, number) => isEven(number) ? accumulator.concat(square(number)) : accumulator, []) // [4, 16]

Our reducer is combining two concepts: filtering if `number`

is even and mapping `number`

to its square. This sounds a lot like what `filter`

and `map`

already do, but because they receive and return new arrays, we can use them together. Combining smaller functions together to build bigger functions is called function composition.

`const numbers = [1, 2, 3, 4]`

const isEven = number => number % 2 === 0

const square = number => Math.pow(number, 2)

const evenSquared = numbers.filter(isEven).map(square) // [4, 16]

Our newer functional code is easier to read, while still taking advantage of our `isEven`

predicate and our `square`

iteratee. Like any effective software design practice, functional programming lets us separate functionality into simpler units of code (like our functions) that are easier to reuse and test in isolation.