JavaScript curry: what are the practical applications?

45,426

Solution 1

@Hank Gay

In response to EmbiggensTheMind's comment:

I can't think of an instance where currying—by itself—is useful in JavaScript; it is a technique for converting function calls with multiple arguments into chains of function calls with a single argument for each call, but JavaScript supports multiple arguments in a single function call.

In JavaScript—and I assume most other actual languages (not lambda calculus)—it is commonly associated with partial application, though. John Resig explains it better, but the gist is that have some logic that will be applied to two or more arguments, and you only know the value(s) for some of those arguments.

You can use partial application/currying to fix those known values and return a function that only accepts the unknowns, to be invoked later when you actually have the values you wish to pass. This provides a nifty way to avoid repeating yourself when you would have been calling the same JavaScript built-ins over and over with all the same values but one. To steal John's example:

String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( (results[1] == "Resig") + " The text values were split properly" );

Solution 2

Here's an interesting AND practical use of currying in JavaScript that uses closures:

function converter(toUnit, factor, offset, input) {
    offset = offset || 0;
    return [((offset + input) * factor).toFixed(2), toUnit].join(" ");
}

var milesToKm = converter.curry('km', 1.60936, undefined);
var poundsToKg = converter.curry('kg', 0.45460, undefined);
var farenheitToCelsius = converter.curry('degrees C', 0.5556, -32);

milesToKm(10);            // returns "16.09 km"
poundsToKg(2.5);          // returns "1.14 kg"
farenheitToCelsius(98);   // returns "36.67 degrees C"

This relies on a curry extension of Function, although as you can see it only uses apply (nothing too fancy):

Function.prototype.curry = function() {
    if (arguments.length < 1) {
        return this; //nothing to curry with - return function
    }
    var __method = this;
    var args = toArray(arguments);
    return function() {
        return __method.apply(this, args.concat([].slice.apply(null, arguments)));
    }
}

Solution 3

Agreeing with Hank Gay - It's extremely useful in certain true functional programming languages - because it's a necessary part. For example, in Haskell you simply cannot take multiple parameters to a function - you cannot do that in pure functional programming. You take one param at a time and build up your function. In JavaScript it's simply unnecessary, despite contrived examples like "converter". Here's that same converter code, without the need for currying:

var converter = function(ratio, symbol, input) {
    return (input*ratio).toFixed(2) + " " + symbol;
}

var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;

converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km

I badly wish Douglas Crockford, in "JavaScript: The Good Parts", had given some mention of the history and actual use of currying rather than his offhanded remarks. For the longest time after reading that, I was boggled, until I was studying Functional programming and realized that's where it came from.

After some more thinking, I posit there is one valid use case for currying in JavaScript: if you are trying to write using pure functional programming techniques using JavaScript. Seems like a rare use case though.

Solution 4

I found functions that resemble python's functools.partial more useful in JavaScript:

function partial(fn) {
  return partialWithScope.apply(this,
    Array.prototype.concat.apply([fn, this],
      Array.prototype.slice.call(arguments, 1)));
}

function partialWithScope(fn, scope) {
  var args = Array.prototype.slice.call(arguments, 2);
  return function() {
    return fn.apply(scope, Array.prototype.concat.apply(args, arguments));
  };
}

Why would you want to use it? A common situation where you want to use this is when you want to bind this in a function to a value:

var callback = partialWithScope(Object.function, obj);

Now when callback is called, this points to obj. This is useful in event situations or to save some space because it usually makes code shorter.

Currying is similar to partial with the difference that the function the currying returns just accepts one argument (as far as I understand that).

Solution 5

Consider filter function. And you want to write a callback for it.

let x = [1,2,3,4,5,6,7,11,12,14,15];
let results = x.filter(callback);

Assume want to output only even numbers, so:

let callback = x => x % 2 === 0;

Now imagine we want to implement our callback such that depending on scenario it outputs even numbers which are above some threshold number (such number should be configurable).

We can't easily make such threshold number a parameter to callback function, because filter invokes callback and by default passes it array elements and index.

How would you implement this?

This is a good use case for currying:

let x = [1,2,3,4,5,6,7,11,12,14,15];
let callback = (threshold) => (x) => (x % 2==0 && x > threshold);

let results1 = x.filter(callback(5)); // Even numbers higher than 5
let results2 = x.filter(callback(10)); // Even numbers higher than 10

console.log(results1,results2);

Share:
45,426

Related videos on Youtube

Dave Nolan
Author by

Dave Nolan

Updated on July 30, 2021

Comments

  • Dave Nolan
    Dave Nolan almost 3 years

    I don’t think I’ve grokked currying yet. I understand what it does, and how to do it. I just can’t think of a situation I would use it.

    Where are you using currying in JavaScript (or where are the main libraries using it)? DOM manipulation or general application development examples welcome.

    One of the answers mentions animation. Functions like slideUp, fadeIn take an element as an arguments and are normally a curried function returning the high order function with the default “animation function” built-in. Why is that better than just applying the higher-up function with some defaults?

    Are there any drawbacks to using it?

    As requested here are some good resources on JavaScript currying:

    I’ll add more as they crop up in the comments.


    So, according to the answers, currying and partial application in general are convenience techniques.

    If you are frequently “refining” a high-level function by calling it with same configuration, you can curry (or use Resig’s partial) the higher-level function to create simple, concise helper methods.

    • ethan
      ethan over 15 years
      can you add a link to a resource that describes what JS currying is? a tutorial or a blog post would be great.
    • danio
      danio over 15 years
      svendtofte.com is longwinded but if you skip the whole section from "A crash course in ML" and start again at "How to write curried JavaScript" it becomes a great introduction to currying in js.
    • gsklee
      gsklee almost 11 years
      This is a good starting point to understand what curry and partial application really is: slid.es/gsklee/functional-programming-in-5-minutes
    • phatskat
      phatskat over 10 years
      The link to svendtofte.com looks to be dead - found it on the WayBack machine though at web.archive.org/web/20130616230053/http://www.svendtofte.com‌​/… Sorry, blog.morrisjohns.com/javascript_closures_for_dummies seems to be down too
    • RobG
      RobG about 10 years
      BTW, Resig's version of partial is deficient (certainly not "on the money") in that it will likely fail if one of the pre–initialised ("curried") arguments is given the value undefined. Anyone interested in a good currying function should get the original from Oliver Steele's funcitonal.js, as it doesn't have that problem.
  • Dave Nolan
    Dave Nolan over 15 years
    Why is it better to curry the higherup function rather than simply call it with some defaults?
  • Dave Nolan
    Dave Nolan over 15 years
    Thanks Hank - please can you expand on when it is useful in general?
  • gizmo
    gizmo over 15 years
    Because it's highly more modular to be able to curry a "doMathOperation" with an addition/multiplication/square/modulus/other-calucation at wish than to imagine all the "default" that the higher function could support.
  • santiagobasulto
    santiagobasulto over 12 years
    This is great! I see it similar to the lisp quote that says "Lisp is a programmable programming language"
  • Prisoner ZERO
    Prisoner ZERO over 12 years
    Okay...maybe I'm dumb...but I have no idea what you mean?
  • Nathan Long
    Nathan Long over 12 years
    Interesting, but this example doesn't appear to work. offset+input will be undefined + 1.60936 in your milesToKm example; that results in NaN.
  • AngusC
    AngusC over 12 years
    @Nathan - offset can't be undefined - it defaults to 0
  • Roboprog
    Roboprog about 12 years
    From what I've read (just now), "curry" is not normally part of a Function's bag of tricks, unless you are using the Prototype library or add it yourself. Very cool, though.
  • hacklikecrack
    hacklikecrack over 11 years
    The same can be acheived with ES5 bind() method. Bind creates a new function that when called calls the original function with the context of its first argument and with the subsequent sequence of arguments (preceding any passed to the new function). So you can do... var milesToKm = converter.bind(this, 'km',1.60936); or var farenheitToCelsius = converter.bind(this, 'degrees C',0.5556, -32); The first argument, the context, this, is irrelevant here so you could just pass undefined. Of course you would need to augment the base Function prototype with your own bind method for non ES5 fallback
  • Shawn
    Shawn almost 11 years
    Could you include the curry function you are using to make this example more complete?
  • Olivictor
    Olivictor about 8 years
    I find this very expressive. Thanks!
  • Admin
    Admin almost 8 years
    This is really a bad answer. Currying has nothing to do with partial application. Currying enables function composition. Function composition enables function reuse. Reuse of functions increases code maintainability. It's that easy!
  • tom redfern
    tom redfern almost 8 years
    When copying a pasting your answer wholesale from another website you must additionally wrap the copied bit in quotes. See stackoverflow.com/help/referencing
  • DR01D
    DR01D almost 7 years
    Your code is much easier to understand than Prisoner Zero's and it solves the same problem without currying or anything complex. You've got 2 thumbs up and he has almost 100. Go figure.
  • ZunTzu
    ZunTzu almost 6 years
    var milesToKm = input => converter.curry('km', 1.60936, undefined, input) is a better solution. It is not sensitive to the parameter order. Currying is overrated in JavaScript.
  • Callat
    Callat almost 6 years
    @ftor sir, you are a very bad answer. Currying is obviously about making functions more tasty. You clearly missed the point.
  • aestheticsData
    aestheticsData almost 3 years
    oftentimes it is said that currying is useful for function composition, but I can write a compose function without requiring currying if all my composed functions take one argument. Currying is needed when one or more of the functions take more than one argument.