How to Add Functional Programming to any JavaScript Project
By: Prescott Breeden
Tags: Functional Programming, JavaScript, Beginner

FP and JavaScript

I absolutely love functional programming (FP). For me it is like Vim — once I committed to learning it, it is hard to imagine life differently. However, many people take an all-or-nothing perspective which can be both confusing and overwhelming to a beginner.

Historically, there are two camps that the FP community have divided into. Pure languages: such as Miranda and Haskell which are pure implementations of lambda calculus; and impure languages: such as Scheme and Standard ML which augment lambda calculus with various effects including assignment, exceptions, and continuations (Walder 1995). This may sound confusing or even blasphemous if you are familiar with FP; however, I would attribute this largely to the way that FP is typically taught.

In every field of study there is a disconnect between the evolution of things and the implementation of them and computer programming is no exception. As human beings, nuance is a difficult hurdle because of the way we try to compartmentalize information, so the easiest way to think about an old problem in a new way is to take on extreme positions which is where I would say a lot of FP information has landed. This polarization makes learning FP a little easier in many respects, but it carries a double-edged blade of losing an important pragmatism.

At the end of the day, programming languages are the human semantics of computer logic and FP is a choice the programmer makes, and it can extend throughout or for as little of the application as you like when you work with impure languages. Arguing that FP can only be done properly with pure languages is like arguing that a machine can only be properly built with metric nuts and bolts.

Now that isn’t to say that some languages won’t make your life a living hell if you try to write them in functional ways, or that some won’t have straight-up limitations that you won’t be able to avoid. However we shouldn’t throw the baby out with the bathwater and JavaScript (which is based on Scheme) is a terrific language to learn FP concepts with if you are already an intermediate to advanced JavaScript developer. In fact, JavaScript can offer some efficiency benefits that some pure FP languages can struggle with. For example, writing point-free compositions in JavaScript is child-play, but in some pure FP languages this can be about as difficult as making sense of Ulysses on the back of a mechanical bull cranked to ludicrous speed. Suffice to say, JavaScript is an excellent language to write functionally with and if you’re a hater, well that’s your prerogative.

Rethinking Utilities

The easiest way to really start tinkering and growing with FP is by composing utility functions. One of the habits we develop when we are in a mutative-OO-frame-of-mind is writing code that updates some sort of state outside of the function body. Utilities, on the other hand, are generally written to be used all over the place with no concept of a state outside of itself — so by focusing your energy here you won’t have to concern yourself about side-effects.

Many JavaScript developers will start off any new project by installing a library like Lodash to have a handy set of utilities written, tested, and ready to go out of the box. Once a project begins to increase complexity, it is common to then use these library-driven utilities in the creation of new utilities to handle common but project-specific functions (e.g. getUserEmail or isApplicationValid, etc.).

Lodash is a terrific library, but problematically all of the functions have their parameters backwards. For instance, map takes a list as its first argument and a function second, however the function is always guaranteed to be known before the list it will operate on because the function has to be defined before the program runs — thereby preventing us from using any partial application. So if you are locked into a project that is using Lodash or another library which also uses backwards parameters, you might have to make yourself a file of FP-compatible equivalents. In time, Ramda is an alternate library that can provide much of the same ready-to-go utilities but written with the parameters in the correct order. For now I would encourage not being overly reliant on Ramda until you feel super confident about how currying and composition are working in the background for you.

With that, let’s get started. The code and exercises are available in this repo.

The Beginner’s Toolkit

To start to rewiring that imperative brain of yours, adopt and master these three functions:

Curry

Compose and/or Pipe

Map

Understanding these three functions will make your journey much lighter on your back because at the end of the day the majority of your code is going to essentially be built on them, so our exercises will focus here.

Importantly, if you don’t understand how the functions work yet, that’s normal and absolutely fine! You are learning how to drive a car right now, not build one from scratch — it will make more sense with time and use and there are thousands of blogs and resources to deep dive any of them individually.

Curry

Curry is a function that takes a function as its argument and returns a new function that allows you give some or all of the arguments required to invoke it.

Let’s take a very simple function:

add takes two parameters and then adds them together, and naturally, we have to invoke it with all arguments to get the result. If we were to curry this function, it will return a new function that will allow us to say “hey, I think I just want to give add just one argument for right now — not two.” By doing so, the function will return a new function that takes the last argument.

The “why” to currying has a simple and not-quite-so-simple explanation. The simple explanation is that sometimes you don’t know all the arguments yet. The not-quite-so-simple explanation is that FP patterns are masterful at reusing and abstracting code through the use of partial application and combinatory logic. In time this will make more sense, but for now, you don’t need to understand how a piston works, you just have to step on the gas pedal and go vroom vroom.

(Note: printResult is basically just a console.log, but with a little flair)

Normally, you will see curry wrapping a function definition (i.e. line 6), however you can also just take any function you want and pass it to curry (i.e. line 2) and voila, you have a function that can be diced up and split into numerous functions. We can call add(2) which returns a new function that adds 2 to an argument, and then invoke that function with add2(1), which returns 3.

Objects are equally important to FP as OO, so a massively helpful application of curry is with the prop function:

Try it out with various functions that use strings, numbers, booleans, objects, lists, and any number of arguments. Get creative, make it crash and figure out why it crashed.

Suggested practice:

subtract, divide, multiply, square (math-y stuff)

getPropertyPerson: takes a property as the first argument and a person as the second argument and returns the property from that person object.

getPersonProperty: same as above but takes the person object as the first parameter and the property name second. Play around with how this changes the result of partially applying it with objects instead of properties.

In many functional languages, all functions are curried by default automatically, which is super cool, but if you don’t really get how it works yet it can also be super confusing. Fun fact, currying is named after Haskell Curry, which is also where Haskell gets its namesake.

When you are feeling comfortable with currying functions, move onto Compose / Pipe.

Compose / Pipe

Compose / Pipe are functions that take any number of functions as arguments and return a new function that passes the result of each function into the next.

Compose and Pipe are essentially the same function, one reads from right to left, the other from left to right. I prefer compose, the right to left version, but I also prefer to play video games with inverted controls, so choose which one makes the most sense to you.

To start playing with compose or pipe, ensure that all functions composed together take just a single parameter. This is actually where all the prep and thinking work will happen when you are figuring out how to use compose or pipe. We are setting up a series of functions like dominoes, and the argument is our finger pushing on the first piece, which falls over and dumps the output of the first function as the argument to the second function, and so on and so forth.

Here, add15 is a single function that is the amalgamation of 5 add functions that will fire in serial from right to left (or bottom to top) and is the equivalent of passing the functions as arguments to each other on line 11. Unless you are an alien, writing out nested function calls is pretty awful to read, but hopefully provides some insight into how compose works. Pipe is the exact same but will execute from left to right / top to bottom:

printAge

Compose / pipe can be notoriously tricky for beginners to debug because it is hard to console.log various steps of the process. One effective strategy for debugging composed functions are to put log statements in the functions being called. This works very well if the function is not being called that frequently, however, if it is being called hundreds of times over a list of data then we will be left trying to figure out which log statement is the pertinent culprit of a runtime crash. The alternative is the use of a trace function:

trace will allow us to check the output between each domino:

This will produce the following output when called with add15(5):

Play around with it, compose / pipe some curried subtracts, divisions, multiplications and toss some objects in the mix as well:

The most important concept that will emerge as you play around with curry and compose is that essentially the “unknown” argument is going to be the data on which the function will operate. Looking at printAge above, the person is the unknown data, and so our composition is set up to receive the data as the argument that tips over the first domino. This will become more natural as you play around with map but another way to think about it is the data that would come from the DB or the API will generally be the parameter defined last.

Map

Map is a function that takes a function and a list as arguments, iterates over that list, and executes the function provided on each item.

Up until now we have been learning new ways to generate functions either through partially applying arguments against curried functions, or by composing multiple functions together to create a new function. The next barrier for us to break is looping and this is where map, reduce, and filter come in to play — however, we will focus exclusively on map for the moment.

Let’s say we are working with an API or DB and we are going to be returned a list of users:

We can transform this array into a new array by defining the function that needs to execute on each user and then passing that into map.

JavaScript built-in map

Since prop(‘name’) returns a partially applied function that just takes a single object as its remaining argument, we can now transform our users from an array of users into an array of strings. This is equivalent to:

users.map(user => user.name);

While the JavaScript built-in is pretty handy, it is a method attached to the list itself, meaning that it cannot be invoked until the data is defined which will have loads of limitations down the road. What we want is a standalone version of map that can be partially applied and disconnected from the data it will eventually operate on:

const map = curry((f, list) => list.map(f));

Now, map can be partially applied and composed with other functions:

Here is a more complex transformation, it is going to use two common utilities, split and head:

Not only are we reusing code more easily, but our code is now declarative instead of imperative — meaning that the code expresses what it does in plain language and they are as easy to play with as Lego pieces.

Now, do not get discouraged if you have a function you need to create that is beyond your level of comfort to build up from smaller pieces. Let’s say I want to create a function that checks if an email is present, and if it is present, return true, otherwise false. Here are three different versions of something that gets the job done:

Because this function is pure in that the same input will always derive the same output and doesn’t affect any state outside of itself, I can still now compose this function with other functions:

At the end of the day, if it works, ship it — however we can also rethink the logic of hasEmail. Essentially, email is a string, and so if our goal is to find out if each user has an email string with a length to it, then hasEmail is actually the combination of other smaller functions:

There are loads of ways to safely build up more complex control flow logic in more reusable FP ways, but that doesn’t mean the original version of hasEmail is “bad” — it is in fact these little steps that will help you start your journey toward monads, monoids, functors, sequencers, and all kinds of neat toys that are both imaginative and (most importantly) fun!

If FP in JavaScript is an avenue you wish to explore further, then you should checkout the phenomenal “Professor Frisby’s Mostly Adequate Guide to Functional Programming”. If it becomes frustrating and confusing, set it down and come back later. It can take time for FP ways of thinking to cement into a brain that has been rigorously trained to think and write imperatively with loops and mutation — however, for most, the reward is worth the journey.

So if you are looking for ways to try and start using FP, take a stab at the repo and try and rewrite some basic utilities, otherwise, keep on keeping on!