Ramda: The Essential Functional JavaScript Library
Functional Programming.
You’ve probably heard of it, lots of developers don’t know what it is. It’s programming with functions right?
Lately, I’ve been doing some research on it and how I can use some of those concepts in some of my everyday coding. Although the concept may seem foreign in comparison to normal object-oriented programming, the fundamentals can be mixed in for cleaner code.
I know I’m blabbing about FP, but I wanted to share a JavaScript library I found that has taken the place of Lodash and Underscore in my projects, Ramda.
Functional Programming Primer
I don’t want to go too deep into this rabbit hole as it can go for quite a while. In order to use Ramda though, a basic understanding of FP will definitely go a long way to using it effectively.
FP can be characterized into one thing: absence of side effects. A function has input, and it has output, and everything done in between those two points should never use anything outside to scope of the function. Here’s an example:
// Not functional
function hello() {
console.log('Hello!');
}
// Functional
function hello(logger) {
logger.log('Hello!');
}
Since the function is referencing something outside of its scope, side effects could happen (i.e. a database call, changing global variables), therefore it’s non-functional. The second function, we pass in all dependencies it requires, making sure that we don’t mess with anything that wasn’t given to us.
The other big part of FP, is everything is immutable. A function should never modify any of its dependencies. JavaScript’s map and reduce methods are good examples of this as they create new instances of the results, never modifying the original list.
You can get a lot deeper if this primer piqued your interest. There’s plenty of additional reading on the web that will have you thinking in functions in no time.
On to Ramda
With all that setup, we can start talking about Ramda and why it’s so useful.
Ramda, like Lodash or Underscore, provides a set of utilities to make interaction with arrays, objects, and functions easier. What sets it apart, and why there was a FP primer, is that it’s focused on being functional.
What does that mean? It means that all functions are curried by default and they are setup so that the data being operated on is the last argument. This allows you to build complex logic through functional composition.
Might be easier to show it:
// Plain JS
var incompleteTasks = tasks.filter(function (task) {
return !task.complete;
});
// Lodash/Underscore
var incompleteTasks = _.filter(tasks, { complete: false });
// Ramda
var incomplete = R.filter(R.where({ complete: false })); // <- returns a function
var incompleteTasks = incomplete(tasks);
You might ask why we need to create a function from other functions? The whole point is now we can use that function with others, hence composition:
// New function to get user's complete tasks var activeByUser = R.compose(groupByUser, incomplete);
The compose function is the bread and butter of Ramda, and Functional Programming for that matter. It allows to make logical constructs of telling the program what to do, rather than how to do it.
Just a note, compose applies the functions right to left, while pipe does the same thing but left to right. Use whichever reads better.
Here’s a function I created to parse the url’s query string and turn it into an object:
var parseQueryString = R.pipe(
R.replace('?', ''), R.split('&'), R.reject(R.eq('')),
R.map(R.pipe(decodeURIComponent, r.invoke('split', ['=']))),
R.fromPairs
);
var query = parseQueryString(location.search);
There’s a lot going on there but you can imagine how much extra code there would be to do that same operation using just plain JavaScript.
The cool thing is how easy it reads. I’m using pipe so it reading if left to right, it’s pretty obvious what each step is doing to the query string.
Wrap Up
There’s a ton of possibilities with Ramda. It can also be used with Node, just npm install ramda –save . Just for the composition factor alone, makes parsing arrays a cinch.
With all that being said, it is not at version 1 as of yet so it is still maturing. You’ve probably guessed as well that overall, this method will be slower in performance than Lodash/Underscore. That’s because of the nature of JavaScript and making a function call be expensive. My argument against that is readability of code over performance, but that’s a decision you as the developer has to make.
If you’ve used Ramda, let me know what you’re thoughts are on it.