I'm learning javascript FP by reading DrBoolean's book.
I searched around for functional programming library. I found Ramda and Folktale. Both claim to be functional programming library.
But they are so different:
Ramda seems to contain utility functions for dealing with list: map, reduce, filter and pure functions: curry, compose. It doesn't contain anything to deal with monad, functor.
Folktale however doesn't contain any utility for list or functions. It seems to implement the some algebraic structures in javascript like monad: Maybe, Task...
Actually I found more libraries, they all seem fall into the two categories. Underscore and lodash are like Ramda. Fantasy-land, pointfree-fantasy are like folktale.
Can these very different libraries both be called functional, and if so, what makes each one a functional library?
There is no clear-cut boundary of what defines functional programming or a functional library. Some features of functional languages are built into Javascript:
Others are possible to accomplish in Javascript with some care:
Still others are part of ES6, and partially or fully available right now:
And there are plenty of others which are really beyond the normal reach of Javascript:
A library, then, can pick and choose what sorts of features it's trying to support and still reasonably be called "functional".
Fantasy-land is a specification for a number of the standard types ported from mathematical Category Theory and Abstract Algebra to functional programming, types such as Monoid, Functor, and Monad. These types are fairly abstract, and extend possibly more familiar notions. Functors, for instance, are containers which can be map
ped over with a function, the way an array can be map
ped over using Array.prototype.map
.
Folktale is a collection of types implementing various parts of the Fantasy-land specification and a small collection of companion utility functions. These types are things like Maybe, Either, Task (very similar to what is elsewhere called a Future, and a more lawful cousin to a Promise), and Validation
Folktale is perhaps the best-known implementation of the Fantasy-land specification, and it is well-respected. But there is no such thing as a definitive or default implementation; fantasy-land only specifies abstract types, and an implementation of course must create such concrete types. Folktale's claim to being a functional library is clear: it provides data types found typically in functional programming languages, ones which make it substantially easier to program in a functional manner.
This example, from the Folktale documentation (note: not in recent versions of the docs), shows how it might be used:
// We load the library by "require"-ing it var Maybe = require('data.maybe') // Returns Maybe.Just(x) if some `x` passes the predicate test // Otherwise returns Maybe.Nothing() function find(predicate, xs) { return xs.reduce(function(result, x) { return result.orElse(function() { return predicate(x)? Maybe.Just(x) : /* otherwise */ Maybe.Nothing() }) }, Maybe.Nothing()) } var numbers = [1, 2, 3, 4, 5] var anyGreaterThan2 = find(function(a) { return a > 2 }, numbers) // => Maybe.Just(3) var anyGreaterThan8 = find(function(a) { return a > 8 }, numbers) // => Maybe.Nothing
Ramda (disclaimer: I'm one of the authors) is a very different type of library. It does not provide new types for you.1 Instead, it provides functions to make it easier to operate on existing types. It is built around the notions of composing smaller functions into larger ones, of working with immutable data, of avoiding side-effects.
Ramda operates especially on lists, but also on objects, and sometimes on Strings. It also delegates many of its calls in such a manner that it will interoperate with Folktale or other Fantasy-land implementations. For instance, Ramda's map
function, operates similarly to the one on Array.prototype
, so R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]
. But because Folktale's Maybe
implements the Fantasy-land Functor
spec, which also specifies map, you can also use Ramda's map
with it:
R.map(square, Maybe.Just(5)); //=> Maybe.Just(25); R.map(square, Maybe.Nothing); //=> Maybe.Nothing
Ramda's claims to being a functional library lie in making it easy to compose functions, never mutating your data, and presenting only pure functions. Typical usage of Ramda would be to build up more complex function by composing smaller ones, as seen in an article on the philosphy of Ramda
// :: [Comment] -> [Number] var userRatingForComments = R.pipe( R.pluck('username') // [Comment] -> [String] R.map(R.propOf(users)), // [String] -> [User] R.pluck('rating'), // [User] -> [Number] );
Actually I found more libraries, they all seem fall into the two categorys. underscore, lodash are very like Ramda. Fantasy-land, pointfree-fantasy are like folktale.
That's not really accurate. First of all, Fantasy-land is simply a specification that libraries can decide to implement for various types. Folktale is one of many implementations of that specification, probably the best-rounded one, certainly one of the most mature. Pointfree-fantasy and ramda-fantasy are others, and there are many more.
Underscore and lodash are superficially like Ramda in that they are grab-bag libraries, providing a great number of functions with much less cohesion than something like Folktale. And even the specific functionality often overlaps with Ramda's. But at a deeper level, Ramda has very different concerns from those libraries. Ramda's closest cousins are probably libraries like FKit, Fnuc, and Wu.js.
Bilby is in a category of its own, providing both a number of tools such as the ones provided by Ramda and some types consistent with Fantasy-land. (The author of Bilby is the original author of Fantasy-land as well.)
All of these libraries have right to be called functional, although they vary greatly in functional approach and degree of functional commitment.
Some of these libraries actually work well together. Ramda should work well with Folktale or other Fantasy-land implementations. Since their concerns barely overlap, they really don't conflict, but Ramda does just enough to make the interoperation relatively smooth. This is probably less true for some of the other combinations you could choose, but ES6's simpler function syntax may also take some of the pain out of integrating.
The choice of library, or even style of library to use, is going to depend on your project and your preferences. There are lots of good options available, and the numbers are growing, and many of them are improving greatly. It's a good time to be doing functional programming in JS.
1Well, there is a side-project, ramda-fantasy doing something similar to what Folktale does, but it's not part of the core library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With