12

I was struggled to find a real-life example of using curry function and get the benefit of using curry.

When I google curry function I often see the example like

let add = x => y => x + y;
let add10 = add(10);
console.log(add10(20));

I have to say I really don't see the value of using curry in this example.

After reading through the answers in this SO https://stackoverflow.com/questions/113780/javascript-curry-what-are-the-practical-applications I still don't see the benefit of using it.

For example, the highest score answer give an example of converter, but that example can be rewrote without curry as another answer shows.

I also read through the answers What is the advantage of currying? (although the discussion are not confined to javascript) I still get the feeling that the curry version can be rewrote without curry(in js).

So can someone show me the "real" advantage/benefit of using curry in javascript?

--- update 2021.10.22 ---

I want to provide an answer to my own question because now I have a better understanding of curry. But the question was closed so I provide this update as my answer.

Only after I study Ramda, which uses curry function as the basic building block, do me finally appreciate the usefulness of curry.

Reading the articles on the ramda website like Why Curry Helps, Favoring Curry, Why Ramda? showing how to put "function first,data last", we then can chain a group of functions together and get the final version of a function that work on data directly.

So to answer my own question "A real-life example of using curry", the example of the promise chain in to process data in "Favoring Curry" is a very good one (although with async/await it may not to seem too appealing)

To Robert Harvey, can you please not to delete my update this time or let me know how can I answer it ?

10
  • see How do I explain ${something} to ${someone}?
    – gnat
    Dec 25, 2018 at 5:48
  • 2
    I agree that most of the basic examples of currying that you find online are extremely unimpressive.
    – user949300
    Dec 25, 2018 at 6:36
  • @user949300 BTW, I really don't understand why my question got down voted. Isn't a "valid" question when you think about js curry? I have worried it will be closed at SO so I asked here. :( Dec 25, 2018 at 10:41
  • I found currying mostly useful when an external lib function expects a function (e.g callback) that takes a given number of arguments and you have a function (e.g handler) that takes more arguments, but you want to pass constant values for these additional args. Partial copy is then more readable than making an arrow function
    – tutuDajuju
    Dec 25, 2018 at 21:02
  • 3
    "I still get the feeling that the curry version can be rewrote without curry" – This is kind of trivial, since that's what currying is all about. The whole point of currying is the observation that any function of n parameters can be rewritten as a function of n-1 parameters which returns a function that takes the nth parameter. Also note that this statement is true of pretty much everything. Every for loop can be rewritten as a while loop. Every if statement can be rewritten as a while loop. Every while loop can be rewritten as a goto. That doesn't mean they aren't useful. Dec 26, 2018 at 11:22

2 Answers 2

11

I've hardly ever used Currying myself, but here's a recent example where it proved useful. I was coding for the game Battlesnake, but this would apply to many games. They provide you with various arrays, giving the location of your snake, enemy snakes, and food. Let's say you are considering a move to a certain {x,y} point, and you want check if it contains another snake, food, or even yourself. The first pass would be to write code like this (I'll use a mix of function and new fangled arrows)

// utility function
function samePoint(p1, p2) {
  return (p1.x === p2.x) && (p1.y === p2.y);
}

and somewhere in the code go

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some((p) => samePoint(p, possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Not bad, but, since you will doing this many many places in your code, a bit tedious and clunky. And, from my experience, easy to mess up the two arguments. :-( The underlying problem is that some() (or find()) accept a function taking only a single argument, and you really need two arguments, the two points. So, you think of currying! Here many would use arrows, I find nested functions clearer:

function samePointAs(p1) {
  return function(p2) {
    return samePoint(p1, p2);
  }
}

Then, your "is that food" test becomes

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some(samePointAs(possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Is this going to make you an Internet millionaire? Probably not. But it does simplify, and, in this case, clarify your code.

3
  • Hi I like you example so I marked your answer as the accepted answer. Thanks. Dec 28, 2018 at 2:42
  • Hi, my question is put on hold. It even got a delete vote. I was trying to edit it to make it be put off hold without avail. I was wondering can you help me edit it? Jan 3, 2019 at 1:27
  • 1
    Hi I finally appreciate the usefulness of curry after study ramda, check my update if you still have interest. Dec 7, 2020 at 10:14
15

Currying in your example doesn't really make sense, I agree. To see the functionality of currying, you need to combine it with higher order functions: functions that takes another functions as parameter.

The most typical example of this is map, filter, and reduce, though another common situation is callbacks. When you partially apply a function, you can pass the partially applied function to these higher order functions. Currying makes sense when most of the time you'd want to use a function is for a partial application so that it can be passed to another higher order function.

A more illustrative example might look like so:

let array1 = [1, 4, 9, 16];
let add = x => y => x + y;
array2 = array1.map(foo ? add(10) : add(20));

Currying is never necessary, yes, as you can always create an anonymous/arrow function from a regular function when you need them, but in some situations it can be very convenient to have curried function compared to regular (and in other situations, it's just making things annoying and slow).

10
  • 2
    "but in some situations it can be very convenient to have curried function compared to regular" so can you give some example of that ? Thanks! Dec 25, 2018 at 6:45
  • @Qiulang one example is if you have a series of configuration logic that controls how to call a function that have lots of parameters. If you don't have curried function, you'll often have to create an object that have a fluent API, or provide some sort of clone_and_update() method, or you'll have to create a separate Builder class to build the function parameter incrementally. A typical example of this is an ORM's query builder. With curried function, you can just call the function as normal on each step.
    – Lie Ryan
    Dec 27, 2018 at 9:30
  • @LieRyan In JavaScript, where it is so trivial to create an options "object" using {}, I haven't found Builder classes to be very useful or common. Can you cite some examples?
    – user949300
    Dec 31, 2018 at 2:09
  • 1
    @user949300 Creating twenty objects with ten members that only differs by one or two parameter is not any easier in JS than in any other languages. With immutable builder object that uses fluent interface, you can instead build the base config object then simply branch off to create different argument sets. This kind of pattern may often look too heavy weight in application code, but it's fairly common for library/framework authors.
    – Lie Ryan
    Dec 31, 2018 at 2:34
  • 1
    Point taken, but @LieRyan with the newfangled Object.assign() it's pretty easy to branch off of a base config.
    – user949300
    Dec 31, 2018 at 3:07

Not the answer you're looking for? Browse other questions tagged or ask your own question.