Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
JavaScript is partly a functional language.
To learn JavaScript, we got to learn the functional parts of JavaScript.
In this article, we’ll look at how to use partial application and composition of functions with JavaScript.
Partial Application
Partial application is where we only apply some of the arguments that are expected in a function.
For example, if we have a function with 3 parameters:
const add = (x, y, z) => x + y + z;
Then we can create a function that has the add
function with arguments partially applied by writing:
const add1 = (y, z) => add(1, y, z);
Then we can use it by writing:
const sum = add1(2, 3);
And we get 6.
To generalize this, we can write:
const partial = function(fn, ...partialArgs) {
let args = partialArgs;
return function(...fullArguments) {
return fn(...[...partialArgs, ...fullArguments]);
};
};
We create our own partial
function by returning a function with the partialArgs
and fullArguments
spread as arguments into the fn
function.
Then we can use it by writing:
const sum = partial(add, 1)(2, 3);
and sum
is 6 again.
Currying vs. Partial Application
Currying is good whenever we need to convert functions that take multiple arguments to multiple functions that take one argument.
Situations where we need to convert a function that takes multiple arguments to a callback for map
that only takes one parameter an example of that.
Partial application of a function is useful for any situation where we need to apply one or arguments to a function and return a function that has the arguments applied.
Composition
Composition is where we chain multiple function calls to return the result that we want.
We have many functions that do one thing, and we combine them into one so that we can get the result we want.
For instance, we can compose the array map
and filter
methods by writing:
const arr = [1, 2, 3]
.filter(a => a % 2 === 1)
.map(a => a ** 2);
And arr
is [1, 9]
.
We call filter
to return an array with only the odd numbers.
And then we call map
to square each odd number.
compose Function
We can generalize the compose function by writing:
const compose = (fn1, fn2) =>
(c) => fn1(fn2(c))
Our function takes 2 functions as parameters and then we return a function that calls one after the other.
fn2
is called first, then fn1
is called on the result returned by fn2
.
Then we can use it by writing:
let number = compose(Math.round, parseFloat)('10.1')
We called compose
with Math.round
and parseFloat
.
parseFloat
is called first with '10.1'
and then Math.round
is called on the returned result.
Then number
is 10.
Compose Many Functions
We can create a general version of the compose
function by using the array reduce
method.
For example, we can write:
const compose = (...fns) =>
(value) =>
fns.reverse().reduce((acc, fn) => fn(acc), value)
We created a function which takes an array of functions fns
as a parameter.
Then we return a function that takes a value as the initial value and call reduce
on it to call each function in the array with the returned result.
acc
is the returned result from calling the functions so far, and fn
is the function.
And then we can use it by writing:
let splitIntoSpaces = (str) => str.split(" ");
let count = (array) => array.length;
const countWords = compose(count, splitIntoSpaces)('foo bar baz');
We split the string by the space with splitIntoSpaces
function.
And we get the length of the split string array with the count
function.
And then we use compose
to combine them together.
Once we call the returned function with a string, we get the number words separated by a space.
So countWords
is 3.
Conclusion
We can partially apply and compose functions with JavaScript.
Partial application lets us call functions with some arguments applied.
And composition lets us call multiple functions in a chain.