Hacker News new | past | comments | ask | show | jobs | submit login
Higher-Order Functions in JavaScript (eloquentjavascript.net)
136 points by zatkin on Feb 25, 2015 | hide | past | favorite | 31 comments



I recently read this, worked through the examples, and was pleasantly surprised at the depth and quality. Subsequently we recommended it to our 800+ member meetup group as the top learning resource for new JS programmers. The content is enlightening and enjoyable and could be just the thing for reaching a breakthrough in understanding about functional programming.


Eloquent Javascript was the first programming book that I ever worked through online and subsequently went and bought because I was so happy with it. I was young and playing Diablo 2: LoD and stumbled upon some bot that would let me do Mephisto runs for loot all night, I was amazed with it and went back to the forums where I'd found it and did some reading, this was the book that they recommended for anyone who was interested in learning some programming.

I'd have to say that this book was one of the more gentle and concise introductory books I've ever read and so far I couldn't be happier that it was my personal introduction to JS and programming. It certainly set me leaps ahead in the JS section when I attended a web dev bootcamp. It is my personal go to for any of my friends who approach me about their interest in getting started with programming. Big Nerd Ranch books are a close second but I've only recently found them and begun reading them.


I profoundly appreciate the nostalgia you brought back by talking about Mephisto runs.


It's also worth mentioning Lodash[1] if you're new to this idea of functional programming. They have an awesome description of each function name and they're very closely aligned to the functional terminology.

[1] - http://lodash.com/docs


Lodash is what finally made me get functional programming, because I was able to start using it in small places where it made sense as opposed to diving into it all at once. At first it started out with just map and filter for some basic cases. Then I would peruse the Lodash docs now and then and discover functions that could replace a lot of my iterative, often messy code with something that felt much more elegant, especially with chaining.

With that new-found knowledge, I decided to make my 4th or 5th attempt at trying to grasp clojure and ran through some 4clojure problems. This time I breezed through the problems, and in many cases enjoyed writing it more than I would have in a typical iterative style. I made sure to follow some recommended users to see their solutions as well, which helped reduce much of my parentheses bloat.

My favorite thing about using high order functions has been that provided your underlying functions are tested/correct, you can more easily reason about and test your new functions, particularly when you keep things immutable/side-effect free.

I'm sure I would have gotten to this point eventually without Lodash, but being able to make use of bits and pieces at a time was a major catalyst for me.




Wow, this is wonderful input. I always love finding an overlap in terminology. If you find the same description of something in more than two places, I think it's safe to say that it's some kind of standard definition.


But for a functional library it has strange argument ordering.


There's a variant of lodash with auto-currying and better argument ordering: https://github.com/lodash/lodash-fp

I haven't tried it, but it looks like it could basically replace Ramda (although I feel that Ramda might contain even more FP oriented functions).


After a little bit of use, I feel like lodash-fp is limited by being a simple adaptation of lodash. Lodash's API is designed around variadic functions, which doesn't really work with autocurrying, so a bunch of important options and functionality is lost. On the other hand, working with Ramda makes me miss some of the flexibility of lodash - e.g., not having to use a different map() for arrays and objects.

The optimal functional utility library would be designed with autocurrying in mind from the start, but not shy away from flexibility where it makes sense.


Open an issue (https://github.com/lodash/lodash-fp/issues) for the options you'd like and we'll add alternative API to cover the arguments required.

lodash-fp does this for max, min, & uniq by offering maxBy, minBy, & uniqBy.


I see. Nice :)

My library of choice is http://www.preludels.com


prelude-ls really shines when combined with LiveScript - syntactic support for partial application, currying, function composition, "pipelining" (|>), implicit arguments and so much more really make a difference.

I started writing a comparison between un-sugared JS and LS use for functional programming patterns, here: https://klibert.pl/warsawjs-talk/code.html (for the talk I gave: https://klibert.pl/warsawjs-talk/).

That being said, I'm very interested in mori, immutable-js or lz.js. prelude-ls is nice, but is designed to work with native JS types and provides no extended semantics that I'd find useful. It's still my go-to library when working on the frontend and it probably will remain one, but I'm thinking about contributing some support for other advanced collection types to it.


Here's a good video showing the difference between underscore and lodash: https://www.youtube.com/watch?v=m3svKOdZijA


I love this book for it's, ah, eloquent and inclusive way of describing more advanced JS topics. Definitely of value, even for the more experienced JS dev.


On the topic of functional JavaScript, a few interesting articles and books I have been reading that have helped shed more light on this subject matter. I particularly enjoyed the Functional JavaScript book [2].

[1] - http://www.cse.chalmers.se/~rjmh/Papers/whyfp.pdf

[2] - http://shop.oreilly.com/product/0636920028857.do

[3] - http://stackoverflow.com/questions/36504/why-functional-lang...

[4] - http://scott.sauyet.com/Javascript/Talk/2014/01/FuncProgTalk...


> The second relies on two external functions and is one line long.

> console.log(sum(range(1, 10)));

> Which one is more likely to contain a bug?

I'd say the second one. Because the first one is totally transparent. The second one relies on functions I can't see. Especially the "range" function may cause problems because here it generates the full range, including both delimiters, unlike the range function in e.g. python.

EDIT: functional programming is extremely useful, but I don't think this example really highlights the most important advantages.


but sum and range are able to be tested in isolation and will be reused across the application, making a bug in them more visible - rather than repeating the logic of the loop in every instance where you need a loop. Also, when maintaining the code later, the signal to noise ratio is much higher, you can see exactly what is being attempted, not the implementation details of it.

There are certainly times when you need to see the implementation details or that your needs don't fit the prescribed and available functions (eg, range being exclusive vs inclusive), but then if that is the exception rather than the rule, it will serve as another indicator when you come across that code that `this is doing something different than usual`, so pay attention to the details.


and then you forget range(1, 10) is a half-open interval because it's meant to be used with `length` as in `range(0, foo.length)`


That part has always annoyed me.

But then Python beat me into submission with its seductive collection comprehension... Now I see it as a standard convention, like indexing should start with 0.


This apparently wasn't a popular post, but it makes an important point: for abstractions to be useful, the user must know or be able to look up their precise semantics, and that requires more than a name, as illustrated by the range function here. This is generally well-understood by the people who write software for making software, but not so much in applications-level programming.


Or something like a public forum or google exists, and lots and lots of people continue to hack and talk about things in order to fuzzily define what they think the author meant by a certain term, in the case that it's meaning was lost, relabeled, mistranslated, or otherwise changed somewhere along the way of technological development.

If you understand mostly what everything else is in a system, then people basically swarm around the behavior of something undefined in order to fuzzily define it. It sticks and it does not stick - it depends on whether programmers rewrite the system or the word is forgotten about on some super secure layer of abstraction, or whether it's the word that everyone is teaching and talking about and naming things after.

I don't think words can really express this process, it's pervasive and paradoxical to it's description. You have to assume you understand everything else, before you can label something truly new. Otherwise it's just the same amorphous blob, and the labels keep swapping, and no concepts are really applicable, because they are only observable from a macroscopic perspective of abstraction, except when they are being used, right there in front of the code. It's always the same balance of 'i know some stuff' and 'i don't know some stuff'.


-Is- it well demonstrated here? I think everyone would understand what 'range' means pretty quickly, just by executing it. I can see someone saying "I don't get 'foldl'" (or even worse, foldl vs foldr), and really -meaning- it, but regardless of whether range(1, 2) gives me [1] or [1, 2], I'm pretty sure people would 'get' it just by trying a few examples in the console/shell.


Yes, it is a clear example of an abstraction with semantics not fully explained by the name, and your solution of testing it does not contradict this point.

More importantly, your solution doesn't scale to more complex abstractions, or to more complex properties, such as whether it is thread-safe or what exceptions it could throw. Plenty of bugs result from mistaken assumptions about such things, or simply by overlooking them.


Not Invented Here, amirite? Implement everything yourself, -it's the only way to be sure-.


In ES6 there are iterables that one uses `for...of` with. Rauschmayer of 2ality has said that `for...of` should be used instead of forEach and I wonder how that will affect composability in functional programming. I quite like the concept of iteratables and creating data structures that can make use of for of and generators. I just have thought about how that affects functional style programming.


for..of simply desugars into getting an iterator from the iterable and then iterating it, right?

To compose iterables, you'd presumably work with iterators directly instead of the sugar.


in case anyone missed it, it's by the author of CodeMirror [1], Acorn, Tern, etc. [2]. He also contributes to Rust.

[1] https://github.com/codemirror/codemirror

[2] https://github.com/marijnh


The theory is good, but the specifics of JS syntax, the type system, and the lack of support from the standard library make functional programming much less fun to use than in proper functional languages or even C#.


great book!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: