We switched from underscore to lodash several months ago, and haven't regretted it. The fact that lodash follows semver is huge. Underscore has introduced serious breaking changes in minor point-releases more than once, which is completely unacceptable for a utility library.
The lodash & lodash-compat npm packages now come with modules baked in too.
Perfect for Browserify!
// load the modern build
var _ = require('lodash');
// or a method category
var array = require('lodash/array');
// or a method
var chunk = require('lodash/array/chunk');
This is great. It combines trust and quality with modularity.
Really nice to see that there's now an auto-curried, function-first version, lodash-fp! I've been really attracted by Ramda JS recently for this reason.
I've been looking for some real-world examples of how currying might be useful in javascript. Haven't not used a language which supports currying for any real world project, I'm interested to know how it can help.
I found a page [1] which talks about currying in javascript, then says "Are there practical uses for currying in JavaScript? Not really."
Can you point me at anything which will help me see why it's useful?
var predicateListFunc = function(props) { return R.allPredicates(R.map(R.curry(R.eqProps), props)); }
var compareProperties = R.unapply(predicateListFunc);
var mergeLists = R.unionWith(compareProperties("Property1", "Property2"));
var groupById = R.groupBy(R.prop("Property1"));
var getGroups = R.compose(R.toPairs, groupById, mergeLists);
var groups = getGroups(list1, list2);
With this code I can merge any two lists (list1 and list2) on any two properties (Property1 and Property2), and then group the result. I use this to synchronize client and server data.
I don't know if this answers your question, since I wrote in about an hour of learning Ramda.js, and there might be an easier way of doing it.
This slideshow [1] by one of the authors of Ramda.js goes over a JavaScript example in OO style and refactors it to functional style. Currying is used to complete the refactoring.
I've linked to the slides on currying but you'll need to back up to follow the whole example.
Wow, thanks, that presentation is pure gold! The best thing about FP (and moving into it from the OOP world) I've ever seen: clear, easy to follow, based on a practical example and really presenting the sense behind the use of FP.
There is an excellent talk called "Underscore, you're doing it wrong!". The talk explains how well designed param order with currying leads to very short and expressive code -- and how underscore missed the boat. This aspect of it should be interesting as it's related to this post. It's well worth the watch.
I was just about to post exactly this. Well worth a watch. It was this talk which finally made currying "click" for me. And serendipitously the topic is the improvements currying and swapping args can make to the underscore (or lodash!) API.
I even tweeted to @jdalton on announcement "hey lodash, you're doing it right" :)
One situation where I felt compelled to use lots of currying was when I was working with a promise library for async code. There are lots of little callbacks you need to use and you benefit from having combinators that act as function versions of js operators, like "+", "[]" and so on and currying helps cut down on the number of combinators you need.
That said, I didn't end up being a big fan of it in the end. Other people can get confused by the new abstractions the combinators introduce and whenever you pass the wrong number of arguments to a function you end up with very tricky runtime errors (this isn't an issue in Haskell because the type system checks this for you)
Its been a while since I worked with this so this is kind of a shitty example out of the top of my head:
If you have code that looks like this:
var user_list =
fetch_json()
.then(function(data){
return data.users
})
You can write it more succinctly using a combinator library instead of writing the callback out by hand:
var user_list =
fetch_json()
.then(get('users'))
Similar things also apply on other code that uses callbacks like maps, filters, etc. I also had combinators for other common JS operators (set, "+", "==", ...)
The point where currying comes in is that it lets you define a single "get" function instead of a separate versions for one and two arguments:
//curried
x = get('users', data)
y = get('users')(data)
//non curried
x = get2('users', data)
y = get1('users')(data)
That said, there are some downsides to using combinators instead of writing the callbacks by hand. If you need to debug something the stack traces are harder to follow and currying doesn't play nice with functions like Array.prototype.forEach that pass "extra" parameters to the callbacks.
In the end the feeling I got was that trying to make JS more functional is not worth the trouble. If I could go back I would try to replace the promises with something less intrusive in terms of coding style, such as generators/coroutines.
Yes, I think I've come to the exactly same conclusions in the past, both with regard to promises and curried (or partially applied functions for that matter).
This may only apply to me but I've found that without strong, static typing to help out, my brain starts to melt sometimes trying to workout what heavily curried JS functions actual do without using a debugger.
"A programmer’s pipe-dream is to write code, and be able to use it repeatedly with little effort. It’s expressive because you write in a way that expresses what is needed, and it’s reuse because.. well, you’re reusing. What more could you want? Curry can help.":
It makes the syntax a bit better for combining functions. Seems like a small thing, but with all the complaining about nested callbacks I guess it's good. See Ramda, who came up with this concept, for a deeper discussion of the benefits.
It's extra stuff that should be in the standard library but isn't.
These days, a lot of it is actually in the standard library - for example, array maps - and invoking lodash just calls the es5/es6 built in, with a slightly uglier syntax.
But if you want backward compatibility, you still probably want to use something like Lodash. I'd also argue that Lodash's/Underscore's interface is far better thought out than the standard library. The standard library has so many absurd gotchas, like `["2", "2", "2", "2"].map(parseInt)`. The verbosity of Javascripts lambdas also makes composition of simple parts more arcane looking than necessary, and having a whole bunch of composable/chainable utility functions does a lot to help people write self-documenting code.
> But if you want backward compatibility, you still probably want to use something like Lodash.
A few years ago, sure, but these days I'd use es6-shim. The code will be shorter, have more documentation around the internet, and when old browsers die you won't have to change anything to be on standard JS.
Interestingly, in practice lo-dash actually doesn't proxy through to the native implementation for things like map and forEach. Just using loops ends up being more performant because of some edge cases in the ES5 spec for those methods that lo-dash and underscore don't follow.
The most important feature is chaining and lazy evaluation.
I think the most useful functions are the typechecking utilities (typeof in javascript is the most useless keyword the human kind engineered in a language).
In the end is a very nice library to work with when it does not get in the way (of course, if you are using `_.each([], fn)`, you should think again and use `Array#forEach` or a nice `for`)
It should start being called "the jQuery effect" since it's one of those libraries that comes to be considered by the community as a standard way to patch the environment. Not only that, but some people begin to develop very strong, quirky aesthetic preferences for seeing it in their code.
I also had no idea what this was until I got to the bottom of the page. Looks like a "better underscore.js". They should just say something to that effect upfront.
They used too say that when the project was new. Perhaps now they feel the project is established enough that it can stand on it's own without trying to position it as a drop-in replacement for underscore.
Yeah,the doc sucks a bit because you're supposed to know it's a "fork" of underscore. They could do a better job at explaining why lodash is useful, because it definetly is.It can really reduce the amount of js code one is writing by 2 or 3.
In a nutshell it's a collection of functions that work on arrays,objects and functions.It's a toolbox.
Lazy.js claims to be even faster than both with support for lazy evaluation to boot. Not quite a drop-in replacement like lodash is, but I think it only requires a minor tweak.
I've been playing around with getting Mori[0] more js-like, from more idiomatic function names and argument order (fn as the last argument, released) to playing around with a chaining API. Ideally we should be able to wrap javascript values, manipulate via idiomatic chaining (similar to Lodash), while getting most of the benefits from highly-tuned persistent data structures, lazy sequences, etc.
I've tended to avoid both underscore and lodash because they're both in the slew of monolithic pre-npm libraries, however the lazy evaluation looks interesting. I wouldn't be surprised to find a library that handles lazy eval without all the extra features Lodash brings.
For the shops who don't live and breath js and whose js work is almost entirely browser-based, these monoliths are great. I, for one, am bummed that the js market is moving away from monoliths. e.g. YUI shutting down.
That's an interesting perspective. I don't have any inherent problems with large libraries, but my problem with some of these 'monoliths' is that other libraries start to depend on the entire library when they only need a small piece of functionality that the library provides.
Substack wrote an article [1] explaining some of the problems that monolithic libraries cause in an ecosystem.
With browserify (or webpack) you can require just the functions you want, and only those (and their dependencies) end up in your code base. This is covered in the changelog
lodash offers modules for node, es6, amd, individual npm packages and bundled in the primary npm package so you can even do require('lodash/array/chunk').
I remember trying this a while ago and being disappointed at the amount of dependency code brought in for a rather trivial function, but the modularization is looking much better than it was last time I took a look.
For anyone interested in learning more about lodash, Adam Boduch's "Lodash Essentials" book just got released, and covers everything in v3 (he delayed it to make sure it covered v3).
It doesn't mean it's breaking in PhantomJS. The modern build lacks some iteration fixes for older environments is all. In the case of PhantomJS it's edge iteration of things like `arguments` objects. The modern build won't error out even in IE6.
That's not "furthermore". chain/value also exists in underscore.
Also your code was broken in Lodash 2 (it'd return a lodash object, not a list) and is more broken in Lodash 3 (chains are now lazy), so your code does just about nothing until you force the iterator's evaluation)
lodash v2 offers an Underscore build that aligns its chaining and other API with Underscore providing a full drop-in replacement. However because lodash is a superset of Underscore those using the Underscore build lose out on additional methods, optimizations, & cross environment fixes.
Over the last year Underscore has align more & more with lodash’s API so the need for a separate Underscore build has diminished. If you still need compatibility around some of the edges you should leverage modules in lodash v3 to supplement your Underscore use until the time you can drop Underscore completely.
It's easy to not care when there's no context or indication as to what Lodash might be. Too many links, not enough time.
I did click -- but only because a previous comment made it seem like Lodash was something related to functional programming. If it hadn't been for that comment, I have ignored the post, because I wouldn't have had a clue WTH Lodash was.
Now, sure, people who've already used or heard of Lodash are going to know, but they're probably already following it on Github. :-) The unwashed masses like me won't have any idea.
I guess the key here is to try to make the title give some indication of what the thing is.
Some decisions sound really weird, such as the fact that forEach is now lazy. It is not a standard replacement anymore, and probably break the compatibility for quite a few apps (even if I'm deeply convinced that we should all use the native functions and shim them when needed).
It's only lazy when using the chaining syntax - and that one was never a standard replacement since `_.map(arr, fn)` returns a wrapper around a value and not a value.
// in 2.4.1
_([1, 2, 3]).forEach(function(n) { console.log(n); });
// => logs each value from left to right and returns the lodash wrapper
// in 3.0.0
_([1, 2, 3]).forEach(function(n) { console.log(n); });
// => returns the lodash wrapper without logging until `value` is called
_([1, 2, 3]).forEach(function(n) { console.log(n); }).value();
// => logs each value from left to right and returns the array
Seems that the only apps this change will break are those who are using side effects in a chain. Which is a pretty dubious choice, IMO. Especially given that Lodash is a "functional programming library".