What is Currying
Currying is the process of taking a function that accepts N arguments and turning it into a chained series of N functions each taking 1 argument.
1 2 3 4 5 6 7 8 9 10 |
function add(a,b,c) { return a+b+c; } function curriedAdd(a) { return function(b) { return function(c) { return a+b+c; } } } |
Any use cases or just another FP hype?
Many times, we call issue an ajax call and get a large array of objects in JSON returned like below:
1 2 3 4 5 6 7 8 |
var people = [ { id: 1, name: 'Anita', age: 30, gender: 'F' }, { id: 2, name: 'Mary', age: 43, gender: 'F' }, { id: 3, name: 'John', age: 22, gender: 'M' }, { id: 4, name: 'Paul', age: 25, gender: 'M' }, { id: 5, name: 'Ray', age: 34, gender: 'M' } ]; |
To get the list of record ids, you can do:
1 2 |
var ids = records.map(function(person){ return person.id; }); |
But you may aware that the predicate function like this is very common. Then you may want to create a more reusable function to do that like below:
1 2 |
function(prop, obj) { return obj[prop]; }); |
However, now you have add another parameter that is not able to be used in the map function as it just takes one parameter for the element in the array (ie. person in this example). With currying, you can now turn the 2 parameters function into 2 one-parameter function chain and get the job done below:
1 2 3 |
var getProp = curry(function(prop, obj) { return obj[prop]; }); var ids = records.map(getProp('id')); |
Take this a step further
We can create another function that is you can give it the list as well
1 2 3 4 5 6 |
function(fn, list){ return list.map(fn); } var mapWith = curry(function(fn, list){ return list.map(fn);}) var getNames = mapWith(getProp('name')); var names = getNames(people); |
Apply another function programming technique called composition, you can do the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var filterBy = curry(function(fn, list){ return list.filter(fn); }); var isFemale = filterBy(function(o){ return o.gender == 'F'; }); var isUnder40 = filterBy(function(o){ return o.age < 40; }); var getNames = mapWith(getProp('name')); function compose() { var args = [].slice.call(arguments), fn = args.shift(), gn = args.shift(), fog = gn ? function() { return fn(gn.apply(this, arguments)); } : fn; return args.length ? compose.apply(this, [fog].concat(args)) : fog; } var getFemaleUnder40 = compose(getNames, isFemale, isUnder40); getFemaleUnder40(records); //['Anita'] |
Reference
- https://blog.simpleblend.net/functional-javascript-concepts-currying/
- http://www.datchley.name/currying-vs-partial-application/
Connect with us