Index
- Introduction
- History
- Currying vs partial application
- Partial Application
- Currying
- Who use
- Real world examples
- Conclusion
Introduction
This post is a study about currying, and about partial application too that for my in the beginning of studies are the same thing, this concept is a native feature in a lot of functional program language, this isn’t native in javascript but is possible implement and use this technique similarly.
History
The currying technique takes this name because the mathematician North American Haskell Curry, yes the same honoured for the Haskell program language, Curry Haskell develop the concept of currying of the combinatory logic, created by Moses Schönfinkel.
“The technique of translating the evaluation of a function that take multiple arguments into evaluating a sequence of functions, each with a single argument” - Wikipédia
Currying vs Partial Application
The currying is the process to transform a function that takes multiple parameters to one chain of functions, currying always works with with unary functions, that is, each one function not take more of one argument. However the Partial Application is when we have functions with more arguments, and after execute then she will returns other function with less arguments.
Partial Application
We can get as example a sum function, that in your definition receive two parameters, using this concept, when this function is called she can receive: the two parameters and everything happens normally as usual, or she can receive just one of the parameters, in this case she will returns a other function that will receive the missing parameter, see the implementation of this function in example bellow:
1var sum = function( x, y ) {2 if( typeof y === 'undefined' ) {3 return function ( y ) {4 return x + y5 }6 }78 return x + y9}
Understanding how this technique works, we can use the ES6 and a ternary condition to transform this in something less verbose. We can return the sum function to a constant, use arrow functions without keys already that she always will returns something, and use a ternary condition to verify if the second parameter was passed our nor.
1const sum = ( x, y ) =>2 typeof y === 'undefined'3 ? y => x + y4 : x + y
After this you can call this sum function with more flexibility, passing the two parameters in the same time, or applying she partially.
1sum(5,5) // 102sum(5)(5) // 1034var result = sum(5) // y => x + y5result(5) // 10
Currying
In example below we have a function with name curry, she receive three parameters fn, x and y, in this case fn is a function that receive x and y as parameters, but how usually is, fn not receive all parameters in one single time, he receive the first parameter, execute and return a new function to receive the next parameter, and at the end is executed the function with all that she needs f(x,y).
1function curry(fn) {2 return function(x) {3 return function(y) {4 return fn(x, y);5 }6 }7}89function sum(x,y) {10 return x + y11}1213const result = curry(sum)(5)(5) // 10
In the same way that we made in Partial Application we can write it with fewer lines.
1const curry = f => x => y => f(x, y)2const sum = (x,y) => x + y34const result = curry(sum)(5)(5) //10
In this case the function curry that was created can be reused in other operations in the same way that was used in sum example, with this we can pass our parameters separately.
1const curry = f => x => y => f(x, y)2const sum = (x,y) => x + y3const subtraction = (x,y) => x - y4const multiply = (x,y) => x * y56const result1 = curry(sum)(5)(5) //107const result2 = curry(subtraction)(5)(5) //08const result3 = curry(multiply)(5)(5) //25910const curried = curry(sum)11curried(5)(5) //10
Who use?
The Rambda for example that is a javascript function library, use Partial Application in many functions, where the functions wait your parameters but if you not pass all of the necessary, will be returned a new function and always gonna work as should, see some examples:
1R.add(2, 3); //=> 52R.add(2)(3); //=> 534R.replace(/foo/g, 'bar', 'foo foo foo'); // => "bar bar bar"5R.replace(/foo/g, 'bar')('foo foo foo'); // => "bar bar bar"6R.replace(/foo/g)('bar')('foo foo foo'); // => "bar bar bar"78R.concat('bar', 'foo') //=> "barfoo"9R.concat('bar')('foo') //=> "barfoo"1011R.equals("bar", "bar"); //=> true12R.equals("bar")("bar"); //=> true
Please, give to me real world examples
Maybe just with the mathematical examples the I use above, get a little hard to take this to the reality, and you are thinking: cool, but I will really use this? maybe. One context where this can be apply, that is very common daily, is a request, probably you already see some lines of code looks like this sometimes:
1import axios from 'axios'23const deleteData = id =>4 axios.delete(`https://api.example.com/v1/${id}`)5 .then(response => { ...response.data })6 .catch(error => console.error(error))78const searchData = id =>9 axios.get(`https://api.example.com/v1/${id}`)10 .then(response => { ...response.data })11 .catch(error => console.error(error))1213// ...
Above we have a stretch of a CRUD, two requests, one method get and one delete in a REST API, we can receive as parameter beyond the id the method used by axios, so that in the first execution of function we can save a type of request, and after use this with different id’s.
1import axios from 'axios'23const API = method => id =>4 axios[method](`https://api.example.com/v1/users/${id}`)5 .then(response => response.data)6 .catch(error => console.error(error))789const searchData = API('get')10const deleteData = API('delete')11// ...121314buscarDados('954') // => {...data}15buscarDados('684') // => {...data}
Conclusion
the advantage that you can take of this concepts is the power of write function that wait receive many parameters, but have the control to apply then according to your need, or according you receive then, you can call your functions even if in current time your not have all required parameters yet. And is one more way to write generic functions for be used in different contexts.