Categories
Functional Javascript

Functional JavaScript — Partial Application and Composition

Spread the love

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *