6

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 ----

Except for the answers I got I also find the log example here shows the benefit of using it.

closed as too broad by gnat, Bart van Ingen Schenau, Doc Brown, Greg Burghardt, BobDalgleish Dec 30 '18 at 20:04

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    I agree that most of the basic examples of currying that you find online are extremely unimpressive. – user949300 Dec 25 '18 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. :( – Qiulang Dec 25 '18 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 '18 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. – Jörg W Mittag Dec 26 '18 at 11:22
6

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.

  • Hi I like you example so I marked your answer as the accepted answer. Thanks. – Qiulang Dec 28 '18 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? – Qiulang Jan 3 at 1:27
14

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).

  • 1
    "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! – Qiulang Dec 25 '18 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 '18 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 '18 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 '18 at 2:34
  • Point taken, but @LieRyan with the newfangled Object.assign() it's pretty easy to branch off of a base config. – user949300 Dec 31 '18 at 3:07

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