Introducing Ramda

For the past year plus, my colleague Scott Sauyet and I have been working in our free time on Ramda, “a practical functional library for Javascript programmers.” When we signed up for Frontend Masters “Hardcore Functional Programming with Javascript” workshop, we were surprised to learn that they had selected Ramda to illustrate their examples. With that vote of confidence, we figured it is time to announce the arrival of Ramda.

There are already some excellent libraries with a functional flavor, such as Underscore and Lodash. Ramda includes all of the favorite list-manipulation functions you expect, e.g. map, filter, reduce, find, etc. But Ramda is significantly different from libraries like Underscore and Lodash. The primary distinguishing features of Ramda are:

// Underscore/Lodash style:
        var validUsersNamedBuzz = function(users) {
          return _.filter(users, function(user) { 
            return user.name === 'Buzz' && _.isEmpty(user.errors); 
          });
        };

… you can do this:

// Ramda style:
        var validUsersNamedBuzz = R.filter(R.where({name: 'Buzz', errors: R.isEmpty}));
// `prop` takes two arguments. If I just give it one, I get a function back
        var moo = R.prop('moo');
        // when I call that function with one argument, I get the result.
        var value = moo({moo: 'cow'}); // => 'cow'

This auto-currying makes it easy to compose functions to create new functions. Because the API is function-first, data-last, you can continue composing and composing until you build up the function you need before dropping in the data. (Hugh Jackson published an excellent article describing the advantages of this style.)

// take an object with an `amount` property
    // add one to it
    // find its remainder when divided by 7
    var amtAdd1Mod7 = R.compose(R.moduloBy(7), R.add(1), R.prop('amount'));

    // we can use that as is:
    amtAdd1Mod7({amount: 17}); // => 4
    amtAdd1Mod7({amount: 987}); // => 1
    amtAdd1Mod7({amount: 68}); // => 6
    // etc. 
    
    // But we can also use our composed function on a list of objects, e.g. to `map`:
    var amountObjects = [
      {amount: 903}, {amount: 2875654}, {amount: 6}
    ]
    R.map(amtAdd1Mod7, amountObjects); // => [1, 6, 0]

    // of course, `map` is also curried, so you can generate a new function 
    // using `amtAdd1Mod7` that will wait for a list of "amountObjects" to 
    // get passed in:
    var amountsToValue = map(amtAdd1Mod7);
    amountsToValue(amountObjects); // => [1, 6, 0]

Ramda is available on npm, so please take it for a spin. And please let us know what you think, and how the library can be improved.

Buzz de Cafe 16 May 2014