JavaScript - Curry

javascript

https://www.sitepoint.com/currying-in-functional-javascript/
https://medium.com/@kbrainwave/currying-in-javascript-ce6da2d324fe#.eu7j8p21f
http://javascript.crockford.com/www_svendtofte_com/code/curried_javascript/
http://blog.carbonfive.com/2015/01/14/gettin-freaky-functional-wcurried-javascript/
http://stackoverflow.com/questions/113780/javascript-curry-what-are-the-practical-applications
http://fr.umio.us/favoring-curry/
https://javascriptweblog.wordpress.com/2010/04/05/curry-cooking-up-tastier-functions/

// JavaScript - Curry:

Currying is the process of turning a function that expects multiple parameters 
into one that, when supplied fewer parameters, returns a new function that 
awaits the remaining ones.  Currying is a way to, essentially, pre-fill in a 
number of arguments to a function, creating a new, simpler function:

function printName(first,middle,last) {
  if (arguments.length == 1) {
    console.log("Check C");
    return function(middle, last) {
      if (arguments.length == 1) {
        return function(last) {
          console.log(first + ' ' + middle + ' ' + last);
        }
      } else {
        console.log(first + ' ' + middle + ' ' + last);
      }
    }
  } else if (arguments.length == 2) {
    console.log("Check B");
    return function(last) {
      console.log(first + ' ' + middle + ' ' + last);
    }
  } else {
    console.log("Check A");
    console.log(first + ' ' + middle + ' ' + last);
  }
}
printName('Khai','The','Doan');
k1 = printName('Khai');
k1('The')('Doan');
k1('The','Doan');

// The regular uncurried version:
var greet = function(greeting, name) {
  console.log(greeting + ", " + name);
};
greet("Hello", "Heidi"); //"Hello, Heidi"

// Curried:
var greetCurried = function(greeting) {
  return function(name) {
    console.log(greeting + ", " + name);
  };
};

As you can see, the uncurried version takes two parameters, but the curried 
version takes only one parameter, and returns a function which would take the 
second parameter.  As you can see, the function returned has a closure to the 
first parameter.  So far, we only deal with functions that takes only two 
parameters.  To support function that takes more than 2 parameters, we would 
have to do something like:

var greetDeeplyCurried = function(greeting) {
  return function(separator) {
    return function(emphasis) {
      return function(name) {
        console.log(greeting + separator + name + emphasis);
      };
    };
  };
};

This can get messy.  To address that problem, one approach is to create a quick 
and dirty currying function that will take the name of an existing function that 
was written without all the nested returns. A currying function would need to 
pull out the list of arguments for that function, and use those to return a 
curried version of the original function:

var curryIt = function(uncurried) {
  var parameters = Array.prototype.slice.call(arguments, 1);
  return function() {
    return uncurried.apply(this, parameters.concat(
      Array.prototype.slice.call(arguments, 0)
    ));
  };
};

To use this, we pass it the name of a function that takes any number of 
arguments, along with as many of the arguments as we want to pre-populate. 
What we get back is a function that’s waiting for the remaining arguments:

var greeter = function(greeting, separator, emphasis, name) {
  console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."

We’re not limited in terms of the number of arguments we want to use when 
building derivative functions from our curried original function:

var greetGoodbye = curryIt(greeter, "Goodbye", ", ");
greetGoodbye(".", "Joe"); //"Goodbye, Joe."

The above currying function may not handle all of the edge cases, such as 
missing or optional parameters, but it does a reasonable job as long as we stay 
strict about the syntax for passing arguments.  Some functional JavaScript 
libraries such as Ramda have more flexible currying  functions that can break 
out the parameters required for a function, and allow you to pass them 
individually or in groups to create custom curried variations. If you want to 
use currying extensively, this is probably the way to go.

One thing that’s important to keep in mind when currying is the order of the 
arguments. Using the approach we’ve described, you obviously want the argument 
that you’re most likely to replace from one variation to the next to be the 
last argument passed to the original function. 

Thinking ahead about argument order will make it easier to plan for currying, 
and apply it to your work. And considering the order of your arguments in terms 
of least to most likely to change is not a bad habit to get into anyway when 
designing functions.

function addBase(base){
  return function(num){
    return base + num;
  }
}

var addTen = addBase(10);
addTen(5); //15
addTen(80); //90
addTen(-5); //5

Function.prototype.curry = function() {
    if (arguments.length < 1) {
        return this; //nothing to curry. return function
    }
    var self = this;
    var args = toArray(arguments);
    return function() {
        return self.apply(this, args.concat(toArray(arguments)));
    }
}

function toArray(args) {
    return Array.prototype.slice.call(args);
}

To use it: Just pass the argument to the function.curry method and a function 
will be returned. Use returned function for further currying:

function converter = function(factor, symbol, input){
  return input * factor + symbol;
}

var milesToKm = converter.curry(1.62, 'km');
mileToKm(3); //result here

var kgToLb = converter.curry(2.2, 'lb');
kgToLb(3); //result here 

function addGenerator( num ) {
  // Return a simple function for adding two numbers
  // with the first number borrowed from the generator
  // Look closely, we are using closure on num
  return function( toAdd ) {
    return num + toAdd;
  }
}
var addFive = addGenerator(5);
alert( addFive(4) == 9);

Who do we name 'curry' after?

curry is named after Haskell Curry. Yes, they used his first name for a functional programming language too; not only that, but Curry's middle initial was 'B', which of course stands for Brainf*ck.) http://fr.umio.us/favoring-curry/

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License