Echo JS 0.11.0

<~>
buzzdecafe 3866 days ago. link parent 1 point
The difference is:

_.where(users, { name: 'foo', pets: [] }); // => Array

....


R.filter(R.where({name: 'Buzz', errors: R.isEmpty})); // =>  function

Replies

CrossEye 3865 days ago. link 3 points
In more detail, this would let you decide to build up functions which then could be reused whenever you need them, deciding only at the end whether to pass the data to them to get the results, or skip it to get a new function, which can later be passed the data.

A simpler example might be this:

    // Common setup for both examples

    var add = function(x, y) {return x + y;}
    var numbers = [1, 2, 3, 4, 5];

    // LoDash/Underscore
    // =================
    // If you want to total up the first five numbers, you can do:

    var sum = _.reduce(numbers, add, 0); //=> 15

    // But if you want a reusable function that can total various different lists:

    var total = function(list) {
        return _.reduce(list, add, 0);
    };
    var sum = total(numbers) //=> 15


    // Ramda
    // =====
    // If you want to total up the first five numbers, you can do:

    var sum = R.reduce(add, 0, numbers; //=> 15

    // But if you want a reusable function that can total various different lists:

    var total = R.reduce(add, 0);
    var sum = total(numbers) //=> 15


Notice that in Ramda, the version that creates the function is almost the same as the version that computes the result; you simply leave off the final parameter -- which then becomes a parameter to the new function.  That's because ramda's `reduce` is automatically curried.

Ramda's main contribution is to make it easy to build such functions.  By taking the data parameters last and automatically currying the built-in functions, Ramda makes it very easy for you to compose your data manipulations functions out of simple pieces.

DISCLAIMER:  I am a co-author of Ramda, and therefore biased in it's favor, although I don't think I have anything against Underscore or LoDash, which I've used to great effect in numerous projects.
appz 3864 days ago. link 2 points
_(users).where({name: 'foo', pets: []}); // => function
CrossEye 3863 days ago. link 2 points
This gives you a 'chained' object version of the output, on which you can then run additional functions.  This can be useful in its own right, but is nothing like what buzzdecafe was suggesting in the Ramda example.

Notice that this

    R.filter(R.where({name: 'Buzz', errors: R.isEmpty}));

doesn't mention the `users` list at all.  There's a good reason; it hasn't been applied yet.  The expression above returns a function that is still waiting for you supply the list of users.  So you might assign this function to a variable or pass it to a callback, or in some other way defer executing it until you have that list:

    var buzzList = R.filter(R.where({name: 'Buzz', errors: R.isEmpty}));
    // ...
    var buzzesInAllForums = map(function(forum) {
        return buzzList(forum.users);
    }, listOfForums);

Note that the `users` parameter is not supplied until inside the callback function.  That's in good part what Ramda is about, giving you the ability to compose simple functions that can be combined later.

Of course those last three lines are not how you'd actually do this in Ramda either.  This would accomplish the same thing with less ceremony:

    var buzzesInAllForums = map(pipe(prop('users'), buzzList), listOfForums);

And again, if you wanted this to be a simple function, you could simply leave off `listOfForums`, and you'd get back a function that expects that one parameter.  That's what we think of as the beauty of Ramda.