Hacker News new | past | comments | ask | show | jobs | submit login
Ramda – A practical functional library for Javascript (ramda.github.io)
80 points by bpierre on Nov 28, 2014 | hide | past | favorite | 18 comments



TL;DR, stack frame all the things.

I'm joking (kind of), but I was reminded of this talk about implementing TeX in Clojure [0], in which you are shown the pains Don Knuth took to avoid subroutines calls, ostensibly for performance reasons—such heavy macro usage, for example, that the speaker calls the language a "dialect" of Pascal. Now we have the maxim about programmer cycles versus machine cycles, which is itself getting a little dated because of scale.

Anyway, fun times to be in this field. You might also like the "It's 1982 and I can't believe we're still..." part of the talk, (a.k.a. "Everything's amazing and nobody's happy") for putting things into perspective.

[0] https://www.youtube.com/watch?v=824yVKUPFjU

EDIT Time is on their side though... with tail-call optimization coming to ES6 (just about the only "good part," according to Crockford).


Interesting library... I haven't dug in, but a cursory glance suggests this could just about replace lodash/underscore ...

The build-in currying of most of the methods is pretty cool as well.

For me, it's difficult to break away from using the built-ins such as Array.prototype.map/reduce etc in favor of more functional variants. The same goes for Immutables... I see the value in adjusting the code in terms of explicitness, it's still hard to get used to.

--edit

Is there something built-in to apply all the functions into the current global? I'd rather not have to do...

    var R = require('ramda');
    var propEq = R.use(R.pipe).over(R.get, R.eq);
over...

    require('ramda').assignTo(this);
    var propEq = use(pipe).over(get, eq);


Neither are very elegant, but you could always do something like:

    var R = require('ramda');
    
    with (R) {
        var propEq = use(pipe).over(get, eq);
    }
...Or even:

    var R = require('ramda');
    
    for (var f in R) {
       window[f] = R.f;
    }


Note that with statements kill performance, at least in V8. https://github.com/petkaantonov/bluebird/wiki/Optimization-k...


Destructuring assignment in CoffeeScript helps with this (not globals, I suppose, but well-scoped locals):

  { use, pipe, get, eq } = R
  propEq = use(pipe).over(get, eq)


I'm currently targetting Node 0.11 --harmony for active development, which also has destructuring. It's an option I hadn't considered... I haven't adopted all the ES6 bits, such as es6-style modules in favor of keeping with built-in node patterns, but have been adopting some bits here and there.


You could always do something like this:

    var R = require('ramda');
    for (var fn in R) if (typeof R[fn] === 'function') global[fn] = R[fn];


> Is there something built-in to apply all the functions into the current global?

yes: `R.installTo(global)` will pull all of the ramda functions on the `global` object


... also, `propEq` is already in the lib.


I learned about Ramda reading Scott Sauyet's awesome presentation "Functional Programming using JavaScript" [1].

He does not focus on Ramda (or any library per se), but he uses and explain several of it's functions to illustrate how simple it is to use functional programming concepts and achieve a code with much more quality and readability.

Definitely a must read for those adventuring in this world :)

[1] https://news.ycombinator.com/item?id=8652348


The examples he goes through are awesome, but I feel that this framework is a bit bloated. As he says in slide 135:

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

You can boil down FP on JS to 5 fundamental functions:

* map

* reduce

* filter

* compose

* curry

* forEach (maybe)

the first 3 and last 1 are already available to you on arrays. Compose is a pretty simple polyfill as is curry, I'm not sure if you really need an entire library to add this in for you.


The big difference is to have everything curried by default, and also having the list/object coming as the last argument. But then, I know there seems to have a lot of function, but for the file size, it just gets really handy when you need just this. I.e. You can build your own groupBy with reduce, but having a builtin one is really useful.


Well, if you want to be really minimal, `reduce` obviates the need for `map`, `filter`, and `forEach`. (Then I guess if you want to be all new school with it, you could use tranducers, but that's another story.) What I don't get is why Javascript libraries are so `flatMap` averse. Sure, it's a little harder to explain, but especially with the Promise-like convention, I think it's a quite generalization of `map` in most cases.


(ramda co-author here) I agree the api has gotten a bit, let's say "broad". we're working on modularizing the lib now, and we plan to provide different builds as well as a facility to roll your own.


To me, Ramda is just "underscore, but with a sane API". Never again am I going to guess whether or not this particular function mutates a random argument or not.

Thanks, authors!


The automatic currying caught my eye, way nicer than partial application in underscore


Lo-Dash 3.0 will be getting _.curryRight, _.rearg, & _.ary to complement _.curry. With them you can easily create auto-curried flavors of functions.

  var where = _(_.where).rearg(1,0).curry().value();


I just started substituting Ramda for Lodash in my projects, and it's pretty nice. Really great composability.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: