Composition and Lodash FP
Welcome to the second part of the three part article series on Lodash. In the previous article, we discussed what Lodash is and its pros & cons.
If you missed it, read this before continuing. If you know about it already, read on!
Functional programming is a weird and sometimes unintuitive paradigm. It’s become fairly well known with libraries like React and Redux popularizing it in the JavaScript community, and one could say it was already well supported by JS, but never used as widely as OOP, until recently.
This article aims to introduce beginners to some practices that are used commonly with React and Redux, such as composition, higher order functions and currying. Later, it introduces a module in the Lodash library called Lodash.fp
, which is designed with these exact concepts in mind.
Composition
Building apps is hard. It's easy to write buggy code. Functional programming tries to alleviate some of the common problems with writing large applications. It helps do so by relying on some core concepts, which I'll try to explain in simple words:
Composition is about starting off with small building blocks and combining them to build big, complex things.
A common way to define these building blocks is with functions. I know you probably know what a function is, but let's have a visual notation that is hopefully obvious and at the same time simplifies further explanations.
Let's say you have a function which does nothing more than add two numbers.
In JavaScript, you could write it like:
If we draw this with blocks, we could make something like this...
add
always takes two arguments and returns one value.
Let's see if it complies with our principles of FP.
✅ It is pure, since, for example, add(2, 3)
is always 5.
✅ In JS, it is first class anyway since we can pass it to other functions.
✅ It also treats data as immutable since it isn't modifying its parameters, instead producing a new value, which is a sum of the two.
So far, we're on the right track with programming functionally, but what we'll see next is interesting applications of the fourth concept, composition.
But first, we need to know what a higher order function is.
A higher order function, can take functions as arguments, or even return them. For example, Lodash.map
takes an array and a function and returns an array with the function applied to each element.
Something like:
As blocks, we could draw it like this...
So map
takes a whole function as an argument. That's why we can call it a higher order function.
With higher order functions, we now have half the things we need to master composition. The other is something known as currying.
Currying
Well, not that kind of curry.
Currying is a technique used to break down functions in order to make them more reusable. It's named after the logician Haskell Curry, who has something named after his first name as well.
Currying involves doing the following:
The curried version of our add function would therefore look something like this:
The magic of closures ensures that a
is defined inside the returned function.
In terms of blocks, the new curried version of add looks like this:
Hmm.. so now that add
gives us a function, what do we do with it?
Well, the returned function takes the second argument. So we should just call it.
In terms of code, calling add
would now look like this:
Similarly, if add took three instead of two arguments, it would look like this:
At this point, odds are that you're scrolling up to see who wrote this because it obviously is a crazy person. Why in the world would you do such a roundabout thing when calling add
with arguments separated by commas was perfectly simple and reasonable?
This is because currying gives us a secret weapon that some functional languages have had by default for years: partial application of functions.
This allows you to create a function like addTwo
which takes one argument and adds two to it.
I'll admit that this example is contrived. So let's have a look at a more practical example.
The popular state management library Redux comes with bindings for React. The library is creatively named react-redux
.
react-redux
contains a function called connect
, which is curried.
So... why is connect
curried again?
Couple of reasons.
The title said Lodash. Where's Lodash?
Hold your horses, I'm getting there.
Lodash is a cleverly-put-together library that focuses quite heavily on being functional. But a lesser known fact is that it has a module called fp
, which can be used to program in a truly functional style.
Almost all functions in Lodash.fp
are counterparts of the regular Lodash functions. The difference is that they are curried and take their arguments in the reverse order.
Why data last? It has to do with the fact that it makes composition easier.
In the example above, fp.map
partially applied to firstCaps
lets you apply it to any array of strings to capitalise the first letter of each element. firstCapsAnything
is a maintainable building block. You could do this with regular map
too but it wouldn't be so clean.
In an earlier article, I talked about Lodash and a useful utility called chain
, which lets us apply sequences of operations to data with ease. Like this:
But using chain
comes with some problems:
Lodash.fp
has a remedy. It provides a function called flow
that does something similar.
What does flow
look like? Well if you were to rewrite the above code snippet using flow
instead of chain
, it would look like this:
So flow
first takes a sequence of functions as arguments, then the data that those functions are to be applied to and finally applies those functions in the order provided.
It's interesting to note that each of the functions in the first set of arguments passed to flow
are all partially applied. filter
takes a function, then an array. map
does the same, and uniq
takes just an array, but what is passed to flow
are partially applied versions of the same.
flow
overcomes all three shortcomings of chain
:
What this shows is that the combination of two simple ideas:
By currying together higher order functions and partially applying functions, we get a powerful mechanism that is just as good, if not better, than the magical workings of something like chain
.
The Takeaway ??
We looked at some of the things that make a programming style 'functional'. We saw what partial application and currying are and supplemented them with some examples of how they can be used to compose smaller building block functions into more complex logic.
Hopefully, I've been able to help you appreciate how these simple ideas can go a long way in dealing with complexity and writing clean code.
Notes and further reading
Thank you for reading.
Book a Discovery Call.