Introduction to functional programming in JavaScript (using Ramda.js)

Jonathan Lester
Wealth Wizards Engineering
8 min readAug 14, 2019
Photo by Sean Paul Kinnear on Unsplash

A bit about me

I’ll start this post with a quick intro to me and where I’ve come from.

Hi all, I’m Jonny, I’ve been at Wealth Wizards six weeks and this is my first programming/developing job. Prior to Wealth Wizards I was an IT Technician with 11 years experience providing consumer level support for Apple Macs, iPhone and iPad hardware and software. In February of this year, I gave all that up and started a 16 week coding bootcamp at the School of Code.

School of Code offers a free 16 week coding course based in Birmingham open to applicants of all backgrounds.

That’s right, its completely free and it was honestly one of the best decisions I’ve made.

After 16 weeks we had our demo day, showing off our new talents to businesses in an around the West Midlands.

The purpose of the School of Code is to get more and different types of people into technology, and teach them the skills they need to leap into the industry.

School of Code really is as much about finding work as learning the skills and over the next few days really was an essential part of me getting a job.

Wealth Wizards had supported the bootcamp heavily, providing three guest speakers and I think five mentors so I was well aware of the business, what they did and where they were. My initial impressions of Wealth Wizards made me think they’d be a good fit for me. After passing a code test and an interview, I was offered the job 8 working days after finishing the boot camp.

The reason for all this is that the rest of this post will be heavily flavoured by my experiences on the School of Code bootcamp because it is my only view into coding in JavaScript and Node.js. I’m sure any seasoned developer will tell you though, 16 weeks is not long but during the 16 weeks we covered HTML, CSS, JavaScript, React, Mongo DB, agile development, git and collaborative coding, paired programming and lots more. These topics were picked to give us the best chance of finding work because, in the middle of 2019, these topics are extremely relevant. On the bootcamp we did discuss pure functions, mutability, currying and closures but, all core concepts of functional programming, but since then I’ve delved much deeper in to the subject. All the stuff that follows are things I’ve learned or applied since School of Code, in my professional software engineering career.

Functional Programming in JavaScript

According to Wikipedia, JavaScript is:

JavaScript (/ˈdʒɑːvəˌskrɪpt/),[8] often abbreviated as JS, is a high-level, interpreted scripting language that conforms to the ECMAScript specification. JavaScript has curly-bracket syntax, dynamic typing, prototype-based object-orientation, and first-class functions.

Wikipedia

Lets also look at functional programming:

In computer science, functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.

Wikipedia

Functional programming has many benefits including:

- encouraging pure functions with no side effects, that way we always get the same output from the same input

- code is split into smaller, independent blocks

- it makes testing and verification easier because each block can be tested in isolation

- it leads to more declarative code rather than imperative code

Although JavaScript was not designed as a purely functional language it treats functions as first class citizens so can definitely be used in a functional programming style.

There are several libraries to help with functional programming in JavaScript including Folktale and functional.js, but here at Wealth Wizards we use Ramda.

But what is Ramda?

Making it Easier with Ramda.js

Ramda describes itself as a

library designed specifically for a functional programming style, one that makes it easy to create functional pipelines, one that never mutates user data.

Ramda

At first appearance Ramda doesn’t really make things look too much different, it’s just another library that gets required then used. I found Ramda most difficult when trying to work out what a piece of code is doing, I’ll admit this was probably due to my lack of experience with Ramda but Ramda also tries to stay correct to the mathematical representation of functions which complicates things a little bit more.

The other thing that is somewhat confusing when using Ramda in an existing codebase is the sheer number of functions Ramda has built in, as I write this it’s 255!

Let’s have a look at an example.

Say we have a csv file of the actors, character and episode count for a selection of the Stranger Things characters:

A csv is all well and good for collecting and viewing data but let’s say we want it in a JSON format. We’ll import the file then use a vanilla JavaScript that will turn our csv in to a JSON array:

What a monstrosity that is! Two splits, two maps and so many dots. It’s also worth noting that we have to define our data first. We have to define our data, then say split, then map it, then split, then map it again where we make the JSON object we want.

Doing the same in Ramda gives us:

I’ll admit, this does look quite a bit different and theres some new words: compose, evolve and zipObj. But notice, we don’t define our data till the end and we don’t have to make up variable names in the map. In fact because Ramda curries everything we can define our function and not pass any data until we need it, I’m just calling it straight away so it runs.

That looks far too complicated Jonny, I think I’ll do it the old way.

Wait, let me explain what’s going on line by line (I’ll ignore the requires).

The first row (line 6) declares a constant then opens a Ramda compose. But what is compose? The Ramda docs describe it as:

Performs right-to-left function composition. The rightmost function may have any arity; the remaining functions must be unary.

That doesn’t really help though, well it didn’t help me.

This ends up being one of the core concepts of functional programming, function composition. Functional programming treat functions like any other variable, they can be declared, passed around, stored and called later, This allows us to declare some smaller, single purpose functions then ‘compose’ a functional pipeline chaining those functions together. In our example, the first level of indentations chains the output R.split('\n') (line 12) into R.map(R.compose((line 7).

That looks weird though Jonny, why does start at the bottom? Why is the R.split run first?

Good question, and I’ll admit I don’t understand all of it but… In short, I think it has to do with the mathematical representing of functions; reading right-to-left, or bottom-to-top is accurate to the mathematical notation of composed functions, the Ramda docs shows this for every function, the compose one looks like this:

((y → z), (x → y), …, (o → p), ((a, b, …, n) → o)) → ((a, b, …, n) → z)

It’s complex and I can’t explain it yet but that’s why it read backwards. The other weird bit, the arity/unary bit is to do with arguments the functions accepts. The first function can accept any number of arguments but subsequent functions may only accept one argument: the output of the preceding function.

Line 12, R.split('\n'), splits our csv file line by line so we have an array with each item being a line of our csv, this means we can map over each line.

That array is then passed in to line 7 R.map(R.compose(so we can start mapping over each line. R.mapaccepts a function, which will be called for each item in an array, and the array itself. The array is passed in by our compose earlier so we only need to add the functions. You’ll notice we have another compose… here comes another backwards reading list of functions. The first one to be run is another split, R.split(',') (line 10), this time splitting our line into columns in order to transform our csv in to a JSON array of objects. Once we have that we have an array of columns: [‘Millie Bobbie Brown', ‘Eleven', ‘25’]. This array is passed upwards to our R.zipObj(columns)(line 9). zipObj is a Ramda function that take two arrays, one of keys and one of values and combines them to make and array of objects, perfect for what we need. The Ramda docs are excellent and give good examples of each function, a link to a REPL so you can play with it and a link to the code on github. The Ramda docs can be found here and in the link section of the bottom.

The final part of our map is R.evolve({ episodes: Number })(line 8). This casts our episode count to a number, not a string so we can sort it more easily, not needed for this but it might be helpful in the future. R.evolvetakes in an object with the desired transformations and the object to be transformed, in our case this looks for the episodeskey in our object passed up from our R.zipObj(columns) (line 9) and then applies Number to the value at that key.

That’s it we have built a simple functional pipeline to take a csv and convert it to a JSON array, first we split the data into rows (line 12), then we map over each row (line 7), splitting each row in to an array of columns (line 10), this array is then combined with the column titles (line 9) and finally, we cast the episode count to a number.

The end result is:

We did it! We started with a csv and made a JSON, that’s what we set out to do.

You might well say that still seems too complicated, and two to three weeks ago I’d have probably agreed but I’m coming round to thinking in a functional programming way and I can see the benefits of it. Ramda makes it even easier by giving us a toolbox of useful functions, currying out-of-the-box and it encourages pure functions.

If this interests you or you want to find more the Ramda website does have some useful link but I found these most useful:

That’s all. Thanks for reading this far. Below is a list of all the links I provided:

Links

--

--