Getting started with functional programming

Pure functions

A pure function is which that:

Given the same input will always return the same output.

Does not have any observable side effect. (when you change a variable’s state).

For example

In the following code, we re-assign number value every time we run increment function:

A more functional approach should not mutate variables values:

You will have noticed we are using arrow functions. Get comfortable with them if you are not. Because they are a great tool to write more functional and compact code in Javascript. If you ever programmed in Haskell, you will notice they are very like lambda expressions.

Immutability

An immutable object is an object whose state cannot be modified after created. But… how can you program if you cannot change the state of your objects? Well, you can, but it is a little bit different.

I like to think it works like a relay race. Objects are always the same but each player that takes them and transforms their state.

For example

In the last example values in the array are being mutated, remember: “Mutation is bad!”. We should create a new object with the desired modifications:

Yet, something is wrong with this approach. You have to create a copy over every time you make a little change. When you treat with large amounts of data this will take you a lot of space in memory.

Use a persistent data structures is a good solution to this problem. What is it? It is a data structure that always preserves the previous version of itself when it mutates. It is immutable, as its operations do not visibly update the structure in-place.

There are severals libraries that help you to start using persistent data structures. For example: Mori, Immutable, Lodash, Rambda, etc.

High-Order functions

In Javascript, functions are First-Class Citizens, meaning they are values. So, you can assign functions to variables! This is fundamental for functional programming.

Also, you can pass functions as arguments or return them as the value of other functions. That’s why they get the name of High-Order functions.

For example

As you see, we are using a function as argument for map We can do this because it is a high-order function.

We can even take this to next level using point-free style. It means that arguments of the function are not explicitly mentioned.

For example

Avoid loops

Functional programming doesn’t support flow controls. So, loop statements are not available. It only use functions and functional calls.

But, if you think this carefully, it makes sense. How can you use loops keeping your code stateless?

So how can we emulate the behavior of a loop? Well, we have some alternatives:

Array methods

Javascript offers several options to work with arrays, for example:

Recursion

A recursive function is a which one that calls itself until it doesn’t, for example:

If you allow me, as a general rule I avoid using loops at all costs unless I have not another option

Closures

A closure is the bundling of a function with its lexical environment.

It is created when you declare a function inside another function. Then, inner function has access to the variable bindings in the outer function. Even after the outer function exits.

For example

Composition

Function composition is the process of combining two or more functions to produce a new one. Composing functions is like snapping together a series of pipes for our data to flow through.

The composition f•g(x) (the dot means “composed with”) is equal to f(g(x)).

To perform this mission we have two options: pipe or compose functions. Both help us to create composed functions, but they differs in their implementation. Let’s see:

As you can see, pipe function reduce arguments (functions) from the left to the right, like you read them:

In the other hand, compose reduce arguments from the right to the left.

compose function could be more confusing than pipe . But if you ever programmed in Haskell, it will remember you the “.” operator. Both functions are useful for the task. Their use will depend more on the situation or developer’s taste.

As for the implementation, all the functional libraries for Javascript include these functionalities. Feel free to use what you feel more comfortable with.

Partial Application

This technique allows to fix some arguments to a function call returning a new function.

ECMAScript supports Partial Application today. It could be done through the use of either Function#bind or arrow functions.

bind returns a new function with a custom context and arguments pre-filled.

The method I use more are Arrow functions because is the simplest to me and is easier to read.

Currying

Currying is a simple technique:

First, it takes the evaluation of a function with many arguments. Then, translate it to a sequence of functions, each one with a single argument.

Often unclear how Currying and Partial Application differ:

Currying converts a function of ’n’ arguments into ’n’ functions with a single argument each.

Partial Application is more generic. It occurs when you apply a function without giving a value to all the arguments. Producing a function which takes fewer arguments.

Currying implies Partial Application, but Partial Application not implies Currying.

For example

Observe that sumCurried only accepts y but operates with x . There x is a local variable scoped in a different function. Did you hear something like this before? Exactly, this works because JS supports closures.

Advantages

With currying you get easier reuse of more abstract functions.

Little pieces can be configured and reused with ease, without clutter;

Functions are used throughout.

Memoization

This is the most complex theme in the post and the one I use less, but I think is an interesting tool for you to know.

Memoization is actually a specific type of caching. Caching can refer in general to any storing technique for future use. Memoizing specifically involves caching the return values of a function.

Functions that are expensive to run can be optimized with memoization. It involves using a closure to cache the results of previous calls to the function.

For example

In the following example you can see how memoize works:

Value is calculated: It returns the cached value. Value is not calculated: Program calculate the result and, before returns it, saves it in cache.

I recommend to use a library as Ramda.js which already has an implementation.

For example

When we call memoizedFactorial it will either:

Retrieve the value from the cache

Call the memoize function and store its value in the cache.

Of course, this example breaks our rule of avoiding side effects. Unfortunately, it is quite problematic to use memoization without changing state. Because we have to keep updating our cache.