Hacker News new | past | comments | ask | show | jobs | submit login
Functional Programming using JavaScript (sauyet.com)
199 points by openmaze on Nov 24, 2014 | hide | past | favorite | 85 comments



finally, a slide deck that uses `history.replaceState` instead of `history.pushState`. no more having to hit "back" 90 times to exit the deck. how the latter ever became a pattern is beyond me.

[EDIT] it probably became a pattern because of browsers that didnt implement the history API, so all hashchange events were pushed onto the history stack.


To be honest, using replaceState for this doesn't seem to make sense to me. A user would probably want to go backward and forward through this using browser history navigation (for instance using the navigation buttons on their mouse).

If you're launching a link from a page you expected to come back to, surely opening the link in a new tab would be the way to accomplish this?


personally, i've always used arrow keys, swipes, pgup/pgdn to nav between slides. i want a single-action "exit slide deck to previous page", and the browser's back is the logical place for that to be, imho.


I think the lines between a single page app and full page reloads needs to be blurred. Most people won't know the difference and the back button needs to behave consistently.

For that reason, I think that pushState here would make more sense. The state of the page does, after all, change.


it's not a mental "context switch", though. i think the way android has the back button implemented is very sensible.


Yelp does this with its photo gallery, and it's really annoying.

When the user is in a linear sequence such as a slide deck, photo gallery or similar, the "previous"/"next" buttons don't map to the browser's back/forward buttons, they navigate the sequence. Littering the history with the navigation history of this sequence does not make sense.

However, it'd be nice if browsers could perhaps record the history (perhaps as some kind of sub-tree history), allowing me to see that I not only visited this slide deck, but that I also visited these specific slides.


There's no real distinction. If the slides were implemented as separate pages you would get a new entry in your history as you navigate through each of them. Back doesn't mean to go back to the previous domain; it means the previous page. You don't think the slides should be separate pages, but that would mean you couldn't link to them.


And that's bad. A lot of people pine for the simplicity of the early days of the web, but single-page pagination was arguably even more horribly broken then.


with replaceState, you get the best of both worlds - bookmarkable slides and no history foo.


Except you can accidentally exit the deck when you actually meant to just go to the previous slide.

I don't think this is better personally. I prefer the use of pushState and back button taking me to the previous slide.

If I really want to back all the way out of the slide deck I will notice after a couple of clicks I need to do something further to go 'all the way back' and right click the back button and click a 'non-slide-deck' selection from that menu.


My rule is pushState() makes sense in apps when changing views , say from a "List of X" to the "Edit X" view. The back button should then take me back to a "List of X".

In this case it doesn't make sense as you remain in the "slide" view the entire time.


You could always do it right with `location.replace`, but that was never as common as it should have been.

https://developer.mozilla.org/en-US/docs/Web/API/Location.re...


Making each slide its own navigation event isn't bad, the problem is that browsers somehow still don't let you jump back to the previous website, not sub-page.


What are you defining as a website? A domain? If I have a:

* myname.com/about.html

* myname.com/projects.html

Would you want to jump out of myname.com entirely when you press back? If not, how do you differentiate that from slides with myname.com/slide1, myname.com/slide2?


how do you imagine this would work?


Collapsing entries on the same page in the back button right-click menu.


that may be a good solution, if all hashchanges get grouped.


I'd like to have CMD+Backspace do that.


For those you want to learn the functional programming I'd suggest to immedeately commence looking at Ocaml/Haskell instead to see the real big picture. Because it's of course adorable that you can write map and compose in JS (it's 2014, it can do it everywhere), but FP = many more serious things.


>Because it's of course adorable that you can write map and compose in JS (it's 2014, it can do it everywhere), but FP = many more serious things.

Or you know, stick to JS, because it's of course adorable that you can do functional programming in a functional language (we could do that since the 60s), but having access to the most prevalent language in the web and being employable is even better.


Strong agreement. "Adorable" is exactly how I describe it. Even if it's already producing practical advantage in Javascript, it's mostly a cute toy given how it stacks up against "normal" usage.

Learn Haskell/OCaml and you'll see how to really take this kind of reasoning many, many orders of magnitude upward. Learn Coq/Agda to see yet another meteoric jump.


While I'm not upset that this has been posted here and has been garnering some attention, this talk wasn't designed for this kind of consumption. I have given this talk to two kinds of audiences:

* In a large corporate office with heterogeneous skill-sets among developers, but where almost all had some experience with Javascript.

* Javascript Users Groups

In each case, the idea was to make the case that FP could offer them practical advantages. The goal was definitely not to teach them FP or to suggest the best FP tool.

There are definitely better languages in which to do FP. But if for whatever reasons you're working in Javascript, I would suggest that a functional style could be useful.


For that audience I agree with dipping toes. I just want to place hedges and guards against making "FP" (whatever that means) out to being better syntax for some kinds of streaming operations when it has much, much more to offer.


I hate to be this guy, but learning FP techniques that aren't available in my day to day language isn't terribly exciting. I want to see a short term benefit, so JS or Java focused articles and books are golden for me.


The issue is that if you're going to be doing FP, you'll want to use a language in which it's not just possible, but natural and happens without an uphill battle. Similarly, if you're just trying to learn the concepts, you're going to have a lot of noise distracting you if you use a language like JS, etc in which FP concepts are quite unnatural to express.


>The issue is that if you're going to be doing FP, you'll want to use a language in which it's not just possible, but natural and happens without an uphill battle.

Most FP paradigms are natural and quite easy in JS.

And learning Haskell can also be described as an "uphill battle".


I think he was referring to Java


Or, you want to use it in your day-to-day job where it might exist thousands upon thousands of lines of code in a not-so-FP language. I think just learning the concepts is great start. If you could rewrite your whole app, please do so. If not, see if you can write some parts with more FP style code. Like using LINQ in C# instead of rewriting everything to F#, or with Java 8 start using streams and other concepts.


While I am currently trying to teach myself Haskell for exactly this reason (understand the "real big picture" in FP), I don't know if there is much harm in starting the journey by exploring some FP concepts in languages one is already familiar with, despite how lacking the language is in that regard. This presentation does point out many features that JavaScript lacks from "true FP" languages.

I, for one, don't know if I would have ever tried to start learning Haskell if I didn't discover some of the benefits of FP first hand through a familiar language.


I'm currently in one of the last chapters of Learn You a Haskell for Great Good (http://learnyouahaskell.com/), which is a really nice introduction into functional programming in general and the kind of thought process behind it. It also really helped me thinking recursively and out of the procedural/OOP box (and also learning Haskell, of course). Learning about FP has been the most eye-opening thing I have done since I'm programming.


I've been wondering lately, if we skip performance as a consideration (for example lazy evaluation), what is the difference between functional programming and imperative programming without globals, pointers, mutable variables or shared memory? In other words, would an imperative language without side effects (that could do static code analysis) be any different in practice than FP?

I'm very serious about this, because as far as I can tell, the next best aspect of FP might be first class functions, but those are starting to be used more in mainstream languages (at least the technique of applying transformations on generic data rather than writing special classes everywhere or using templates).

I'm beginning to feel that the real advantages of FP are being obfuscated by unusual syntax. There should be no reason why we can't go from some of the FP notations to the plain old algebra style (x=y) of C-style languages like Javascript. With better references and immutable variables, we should be able to split calculations up over several lines and have the compiler figure out how to optimize it into basically FP code.

P.S. I do know lisp, so I'm asking for a rather more enlightened answer than just to research it further.


Consider one particular case, where we need to read in a gig of data (made of many records), filter out some records, compute some stream of transformed versions of those records, and then write out the rolling average.

This actually sounds pretty nice to write as a shell pipeline (and that's a really good way to do it), but really, it's likely that you'd end up writing some code like

    main() {
      q = queue(5);
      avg = 0;
      while(!eof) {
        r, eof = get_record();
        t = transform(r);
        if(q.size() >= 5){
           avg -= q.pop();
        }
        avg += t;
        q.push(t);
        print  avg/q.size();
      }
    }
or something, but it'd actually be annoying to extract out the logic for handling the rolling average and split it out from the looping code, at least if you want to maintain constant memory use, and if you had to do something similar in a few places, you'd end up duplicating code.

I claim that it's possible to factor that code nicely out in Haskell, and still get the compiler to generate the same machine code as the C loop. This doesn't particularly use first class functions, and more relies on the combo of sufficiently smart compiler and sufficiently strong guarantees about what code will do.

I also take slight offense at calling C-style languages "plain old algebraic style", since it'd be really strange in algebra to say both x=5 and x=6. I would not hesitate to call FP languages where you can substitute equals for equals and such the algebraic languages.


Pure FP is very different from imperative languages because it has no notion of temporal order. You can (in truly pure FP) evaluate things in whatever order you choose and stop as soon as you're satisfied. The language cannot care at all [0].

That said, FP often involves the introduction of monads which restore sequencing (along with many other beneficial effects). A monadic FP computation is very similar to a plain imperative computation... just with all of the arbitrary details automatically selected to be coherent and optimal.

You can even pretty easily embed OO in FP languages (though it gets a little hairy sometimes) since as soon as you can simulate open recursion somehow you can get late-binding as you like. See Oleg's O'Haskell papers for this kind of nonsense.

[0] In this regard, even Haskell is impure since it allows for non-terminating computation which can be seen as an impurity since you cannot expect to just evaluate `let x = x in x` repeatedly and get anywhere meaningful. Other languages like Coq, Agda, Idris are terminating (thus not Turing Complete) and therefore truly pure.


Thank you, I hadn't considered that FP can evaluate in arbitrary order or simultaneously. That makes sense, because if there are no dependencies between code paths (so no side effects) then there's no reason they can't be executed at the same time. They didn't mention that back in the Scheme course I took in college, and I think something vitally important was lost on us (although in fairness they did emphasize that the code was evaluated, not run sequentially).

Seeing how monads reintroduce temporal dependence is also an astounding insight, and I can't believe that I've never seen them described that way. That means that the monad has more in common with, say, the mutex, than it does with I/O. I've always tried to approach them with metaphors like sockets and utterly failed to grok anything for more than a couple of days.

I'm thinking that if Haskell is an "impure" functional language, then I would like to see a "pure" imperative language. I envision it as similar to Go but multithreaded and basically every function in the language would be its own process, communicating with sockets (so basically a shell with C-style syntax). The overhead could be largely eliminated with a stackless context switcher. It wouldn't be able to achieve the optimization of FP but it might be more approachable to the mainstream and by extension maybe iterate faster and lead to higher productivity. I’d like to see it take the place of OpenCL/CUDA and SIMD because I find them tedious compared to more elegant languages like MATLAB/Octave.


I'd suggest taking a look at Coq if you want something more pure than Haskell. I'll warn you that this comes with some degree of added sophistication! Coq is not just a programming language but instead a proof system which can be used to verify programs as correct (not just unit tested) and then extract the skeletal, underlying program as OCaml, Haskell, or Scheme code.

http://adam.chlipala.net/cpdt/

True purity actually doesn't look much like Go at all. Instead, it means that every expression literally can be evaluated and replaced with its value in a completely arbitrary order. This massively simplifies the meaning of a language and opens it up to bear much more structure (such as that of a mathematical proof).


Idris is Turing Complete. Total functions are opt-in.


Idris' opt-in totality is a weird beast since those opts are extralinguistic. I really consider it to be a downside when a language is turing complete these days—I'd rather Idris just use a partiality monad.

So, maybe I'm just using the power of wishful thinking with my characterization above.


It's different in practice because languages have built-in "opinions" (often codified by syntax, or the standard library, or other ways) that heavily influence their ecosystem.

Functional javascript, or python, is not awesome because the default datastructures are mutable, and the ecosystem of libraries are written in an OOP style using mutable data structures. There is some small value in writing the code you control in as FP a way as possible, but you aren't going to have a ton of success in that unless you are willing to rewrite your dependencies to also be more functional.

ReactJS may be a killer app that can influence javascript's "opinions" at the ecosystem scale, but that is going to take more time. I've been using ReactJS since it came out as tech lead on small teams, and it was not without challenges to get an OOP trained team to use React well, and to avoid the OO parts of React.

Edit: In theory, yes, if you could somehow statically enforce that your C code (and dependencies, including the OS) have no side effects, then some hypothetical compiler could combine your imperative C statements into functional expressions, though I don't know what advantage that would give you. Maybe I have misunderstood your post.


> I'm beginning to feel that the real advantages of FP are being obfuscated by unusual syntax.

Or that unusual syntax is precisely motivated by trying to seamlessly and naturally express FP code.

Either that or they were just being intentionally obtuse... come on, man. Which sounds more likely of these two? I'd personally never want to program in a language with the semantics of Haskell, and the syntax of a C-like language.

> With better references and immutable variables, we should be able to split calculations up over several lines and have the compiler figure out how to optimize it into basically FP code.

Or just dive the code up into whatever temporary and intermediate steps that you need with let-in expressions and where-declarations? I mean, why not? If what you want the compiler to process is FP code, then just divide it up like you would divide up FP code. FP /= one liners.


While I love and use Haskell a lot I would recommend Purescript [0] over Haskell or Ocaml.

Even if the only reason (hint: it's not) were that Purescript uses familiar tooling such as NPM, node, CommonJS modules, bower, etc and would allow users to focus on learning functional programming faster.

For those that wasn't more than the examples, there is the wonderfully comprehensive, practical, and just plain fun Purescript book[1].

0: http://www.purescript.org/

1: https://leanpub.com/purescript/read


Edx has a course in functional programming using Haskell. I haven't taken it yet but I'm going over Christmas.


Introduction to Functional Programming https://www.edx.org/node/2126#.VGrvnnVGh5Q


I'm a huge fan of lo-dash, but might switch to Ramda. Here's a rundown:

http://bahmutov.calepin.co/lodash-to-ramda-example.html


The author is misrepresenting imperative code [0]. Instead of the 42 lines of code he thinks is imperative, but really is already functional-compatible, this is what I would write:

    var getIncompleteTaskSummariesForMember_imperative = function(memberName) {
        return fetchData().then(function(data) {
            var tasks = data.tasks;
            var results = [];
            for (var i = 0; i < tasks.length; i++) {
                var task = tasks[i];
                if (task.member == memberName && !task.complete) {
                    results.push({
                      id: task.id,
                      dueDate: task.dueDate,
                      title: task.title,
                      priority: task.priority
                    })
                }
            }
            results.sort(function(first, second) {
                return first.dueDate - second.dueDate;
            });
            return results;
        });
    }

Still longer than the 10 lines of functional code, but a much more fair comparison.

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


I was bothered by the presented functional implementation; it seemed to use a whole pile of library-specific functions to do the same things base JavaScript already does, just expressed slightly differently.

This would be the code I'd write for the same task, pure JS assuming that fetchData returns an ES6 Promise:

    var getIncompleteTaskSummariesForMember = function(memberName) {
        return fetchData().then(function(data) {
            return data.tasks
                .filter(function(task) {
                    return (task.member == memberName && !task.complete); })
                .map(function(task) {
                    return {
                      id: task.id,
                      dueDate: task.dueDate,
                      title: task.title,
                      priority: task.priority
                    }; })
                .sort(function(first, second) {
                    return first.dueDate - second.dueDate; });
        }, function(reason) { console.log(reason); });
    };
Now, does that count as functional? I'm not sure I really care, but it's certainly JavaScript-ish.


There is also @fogus' book: http://shop.oreilly.com/product/0636920028857.do

I haven't read it yet.


It's a fantastic book for getting your mind used to the functional way of thinking.

I'd also recommend JavaScript Allonge on the same topic. https://leanpub.com/javascript-allonge


For JS people wanting to learn FP, I'd recommend Allonge first. For FP people wanting to see how they can use JS in and FP manner, Fogus' Functional Javascript is a good book, and it's not a bad second book for the JS crowd.


I'm curious what you think about Clojurescript? leaving aside that it may be harder for teams to move to Clojurescript than to improve their JS codebase.

The reason for the question is that Clojurescript supports all the FP idioms of your slides more naturally and also has more FP features.


I've just started learning Clojure, and I haven't spent any time yet on Clojurescript.


This book is great, it is very upfront that javascript has significant limitations if you're interested in functional programming. But, I think it lays out a great way to write much cleaner javascript code and ways to avoid mutability. There are tons of great functions that Michael writes in the book and would be very useful if not only as a set of utility functions alongside underscore.


This is a really nice presentation that introduces a lot of concepts well and also helps a person conceptually understand how functional programming fits in to the larger programming world.

Book mark it and share it.


I agree, a lot of people tout how functional programming is easier to both read and write, but this really puts things in perspective. I especially like how he explains how the different standard functional functions work in very simple terms and immediately shows the advantages of using them.


Intrestingly it seems that the functional version he proposed is much faster than the OO version. http://jsperf.com/oop-vs-ramda


(Author of that talk (and co-author of Ramda) here. Your perf test only times the parsing of the function -- not exactly fair.


Hey man. Great work.


Fixed for actually running the tests instead of just parsing:

http://jsperf.com/oop-vs-ramda/3

TL;DR: Ramda is somewhat faster than OO one


Fixed for running a proper imperative version instead of the functional-oriented 'imperative' version of the original author:

http://jsperf.com/oop-vs-ramda/4

TL;DR: Imperative is faster than functional. Functional is shorter (33% slower in chromium, 83% slower in firefox), but might be more readable depending on your preferences.


Pardon me if I read it wrong, but you just removed the promises, didn't you?

Anyway, doing the same to the FP version yields almost equal speeds (Chromium):

http://jsperf.com/oop-vs-fp


I removed all the useless promises, yes.

The one remaining is the one after fetchData, which looks like it could be async and make use of a promise.

It only yields equal speeds in chromium (good to know), although if you try in firefox, imperative is still 4 times faster.


I dislike these expositions on the "differences" between object-oriented and functional programming. The two concepts are not directly commensurable, and one can have objects with referentially transparent methods, to be used in a declarative style.


Agreed. Everything about this slideshow seemed like the author was slightly off the mark about what functional programming is and why it's useful.


I believe this is the author of Ramda, yes?

I can't find the talk, anybody got a link?

(Ramda is pretty bad ass.) http://ramda.github.io/ramdocs/docs/


One of the co-authors, yes. Mike Hurley and I have been developing the library for around 18 months. For the last six months, we've had many additional contributors, including some prolific ones, and David Chambers has recently joined the team.


There is no video for this. I gave the talk several times to small groups, but never recorded it. Sorry. But you don't want to see my ugly mug, anyway.


Thanks for that! It was a nice introduction, I have a colleague who usually made my eyes glaze over when he started about FP, but now that I have seen it in an environment that I understand and use in my day to day job, a lot of "a-ha" moments occurred in rapid succession. I also liked the humorous bits. It's all pretty self-explanatory and well put, a little Googling will fill in any gaps an interested pupil might face.


I put together a similar talk last summer: http://thedrearlight.com/functional-js-wut unfortunately, don't have the vid either, but the slides might be complementary to the ones linked by the OP.

--edit It's formatted kinda weird, where both up/down and left/right arrows navigate through the different sections.


Very nice talk! I've used that formatting too, and while it can be very useful when running a presentation by yourself, it's not so nice for slides shared with someone who doesn't know it.


Trying to ride the wave: I have written about functional programming in javascript, see blog posts http://bahmutov.calepin.co/tag/functional.html - Ramda is great!


I've read and commented on many of these posts (the latest one far too frequently! :-) ). Excellent stuff.


His functional example in Bluebird and some ES6 (traceur) just becomes:

``` return fetchData().get("tasks").filter(x => x.member === memberName).filter(x => !x.complete).map(x => {x.id, x.dueDate, x.title, x.priority}).call('sort'); ```


Bravo for promoting functional programming and showing how it can be done in JavaScript. One issue concerns me, though: using strings to reference attributes. This makes static checking tools much less useful and can lead to difficult to find errors due to refactoring and typos.


That, I think, is working with the grain in Javascript. It's extremely difficult to do static checking in the language in any case, because in the language `foo.bar` is just syntactic sugar for `foo['bar']`. A FP approach in JS is by its very nature going to be different from one in something more strongly typed like Haskell; this is actually one of the easier differences to swallow.


Promoting FP using SQL as an example for encoding business logic doesn't look to me like a nice example...


The idea was just to show that, contrary to many people's expectations, OOP is not the only widely used paradigm in business programming.


These slides are very difficult to read on a touch device.


I apologize. I really posted it on my site only as a convenience for myself, not to be published. I never really considered anything but projection at the time. Although I can view it on my fairly large phone, the experience is not great.


See also fn.js (Functional JavaScript Library)| https://bitbucket.org/ktg/fn


I assume these slides are from a talk?


Correct, but not mine. I think they are quite interesting and they are well understood outside the context of the talk


No video was recorded on the occasions I gave the talk. I'd apologize, but actually, you should probably thank me. :-)


The author is here! Thank you, awesome slides and content!


you missed a golden opportunity to rickroll hacker news readers


Hasn't that meme died yet? Well, I for one won't help keep it alive by pointing to the recently discovered talk video found here:....


Can we find the talk somewhere?




Consider applying for YC's W25 batch! Applications are open till Nov 12.

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

Search: