Functional Programming — Composition

Image for post
Image for post
Photo by Joel Filipe on Unsplash

In the last blog, we were talking about curried functions, they are often constructed with composition together. So what is composition? In mathematics, function composition is an operation that takes two functions f and g and produces a function h such that h(x) = g(f(x).

For example:

const f = n => n * 2;
const g = n => n - 1;
const h = x => f(g(x));
h(21); //=> 40

In short, creates a pipeline of functions with the output of one function piped into the input of the next one.

const compose = (...fns) => x => fns.reduceRight((y, f) => f(y), x);

This version takes any number of functions and returns a function which takes the initial value, and then uses to iterate right-to-left over each function, , in , and apply it in turn to the accumulated value, . What we're accumulating with the accumulator, in this function is the return value for the function returned by .

There’s a very similar one called . The difference is the order of the composition. Compose is a right-to-left while Pipe is a left-to-right composition.

And in a way to make it simple, composition is dot chaining:

const doStuff = _.compose(
join(''),
_.filter(x => x.length > 3),
reverse,
_.map(trim),
split(' '),
toLowerCase
)
// the same thing without compositionconst doStuff = str => {
const lower = str.toLowerCase()
const words = lower.split(' ')
words.reverse()
for(let i in words) {
words[i] = words[i].trim()
}
let keepers = []
for(let i in words) {
if(words[i].length > 3) {
keepers.push(words[i])
}
}
return keepers.join('')
}

Finally let’s look at some examples.

const _ = R;const { formatMoney } = accounting;const CARS = [
{ name: “Ferrari FF”, horsepower: 660, dollar_value: 700000, in_stock: true },
{name: “Spyker C12 Zagato”,horsepower: 650,dollar_value: 648000,
in_stock: false,}
];

=================
// use _.compose(), _.prop() and _.head() to retrieve the name of the first car

const nameOfFirstCar = _.pipe(_.head, _.prop("name"));

====================
// Use the helper function _average to refactor averageDollarValue as a composition

const _average = function (xs) {
return _.reduce(_.add, 0, xs) / xs.length;
}; // <- leave be

// var averageDollarValue = function(cars) {
// var dollar_values = _.map(function(c) { return c.dollar_value; }, cars);
// return _average(dollar_values);
// };

// var averageDollarValue = _.compose(_.average, _.map, //_.prop("dollar_value"))
var averageDollarValue = _.compose(_average, _.map(_.prop("dollar_value")));


==================
// Write a function: sanitizeNames() using compose that returns a list of lowercase and underscored names: e.g: sanitizeNames(["Hello World"]) //=> ["hello_world"].

const _underscore = _.replace(/\W+/g, "_"); //<-- leave this alone and use to sanitize

// const sanitizeNames = _.compose(_.map(_.toLower), //_.map(_underscore), _.map(_.prop("name"))) the same as
const sanitizeNames = _.map(_.compose(_.toLower, _underscore, _.prop("name")));


============
// Refactor availablePrices with compose.

// const availablePrices = function(cars) {
// const available_cars = _.filter(_.prop('in_stock'), cars);
// return available_cars.map(x => formatMoney(x.dollar_value)).join(', ');
// }

const availablePrices = _.compose(
_.join(", "),
_.map((x) => formatMoney(x.dollar_value)),
_.filter(_.prop("in_stock"))
);


=======================
// Refactor to pointfree.

// const fastestCar = function(cars) {
// const sorted = _.sortBy(car => car.horsepower, cars);
// const fastest = _.last(sorted);
// return fastest.name + ' is the fastest';
// }

const fastestCar = _.compose(
_.concat(" is the fastest"),
_.prop("name"),
_.last,
_.sortBy(_.prop("horsepower"))
);

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store