I love lodash JavaScript library. It allows me to write short, elegant code without most common logical bugs. Recently, I have tried a different functional library Ramda that has a few additional killer features:
1 - every function is curried by default. This makes it super easy to prefill some arguments with values (in left to right order), leaving the rest free
1 | var add10 = R.add(10); |
Of course, lodash has curry too, but it is not turned on for its own functions.
2 - Ramda includes several functions missing from lodash (but are part of
the separate lodash-contrib library).
There are logical operators, simple arithmetic, but most important:
pipe
function. It is the opposite of compose
and produces code that
is very easy to read.
1 | var x2 = R.multiply(2); |
3 - Ramda puts data at the last position in each function. I like this approach and believe it can lead to more elegant code. In most cases, I first create a function that is like a pipeline, then apply it to the actual data.
For example, let us imagine the following problem. We have an array of objects. Each object has a method that returns either a string or an array of strings. Our goal is to compose a list of unique values from all calls
1 | var items = [{ |
Here is the solution using lodash
1 | var list = _.uniq(_.flatten(_.map(items, function (v) { |
Notice that the order of operations is a little weird. The actual data variable
items
is surrounded by the _
calls and a utility callback calling getNames()
.
We can rewrite this code to get more left to right ordering
1 | var list = _(items) |
This goes against my principle to first create function from the individual steps, then call it on data.
Here is the same code using Ramda and my own
functional-pipeline to fill
missing invoke
feature in Ramda (There is invoker
but it requires all objects to
have a common prototype. If anyone can suggest how to do this in Ramda, please let me know):
1 | // fp comes from functional-pipeline |
Update Same functionality can be achieved without fp
using ramda.func
method
(thanks to @buzzdecafe for solution)
1 | var getNames = R.map(R.func('getName')); |
I find Ramda's functional ordering more intuitive and almost 1 to 1 matching natural English sentence expressing my goal: get names, then flatten, then find unique values.
4 - Ramda's list iterators only pass the item by default. On the other hand JavaScript and Lodash pass the item and index to the callback function. This madness has burnt me several times.
1 | ['1', '2', '3'].map(parseInt); |
You can still have same callback with index and array instance by using R.map.idx
and similar
functions.
Having said all this, we are still keeping lodash in our production code for three reasons
- We are not going to rewrite lots of tested and familiar code. Both libraries can coexist fine.
- Lodash is very well tested and fast. It remains to be seen if Ramda is going to be developed at the same level as lodash.
- Next version of lodash (3.0.0) will include some of the features that might make it easier for the kind of functional pipeline programming I practice.
Update 1
The author of Ramda Scott Sauyet has posted an excellent essay on his philosophy behind writing Ramda the way it is. Read The Philosophy of Ramda.