FPSK: Composition or How to Write Code like Hemmingway

alt

When Hemingway was alive he was widely acclaimed as one the greatest American artists. Besides being known for works such as A Farewell to Arms and The Old Man and the Sea, Hemingway became famous for his emphasis on concise prose.

Hemingway believed that his goal was to convey as much emotion as he could using the fewest amount of words. His emphasis on brevity is something that we as engineers should emulate in our code.

So how do we create great code with clarity? It all starts with functional composition. Functional Composition is about passing functions to one another to create more complex systems. From a mathematical standpoint think of composition as f(g(x)). Where x is some parameter we pass to g which is then passed to f.

But before we dive into how we can compose complex functions lets start with the building block, the function.

Pure Function

The holy grail of functional programming is the pure function. The pure function is one in which there are no side effects. In a pure function the arguments are explicitly declared and something is returned. The key part of pure functions is that we don’t have other behavior happening

var drones = ['Blue Bird', 'Free Bird']; 

function alterName (drones) {
   var alteredResults = drones.map(function(input) { return 'The Original' + input}); 
   return alteredResults; 
};

alterName(drones);
// The key here is nothing is impacted outside the input

With functional programming, we tend think of a function as a mapping. We’re mapping inputs to outputs and every time the same result should be returned. The benefit being we have certainty with our output, without weird side effects.

An added benefit that we get with pure functions is that we can utilize memoization. We'll go more into that when we talk about partial application. However its a powerful tool that allows us to cache results that we've already computed.

Composition:

Now that we have the building block of functional programming, we can start the main show and build truly powerful elements. Lets take a frequent issue we see with front end development which is poorly formatted responses from the server. Take the example of changing a bunch of strings and turn into shortened numbers.

var dronePrices = [72.56,74.09, 100.83, 200.79, 140.7, 50.3, 56.1, 43.1, 90.8, 96.7, 114.2, 278.5]; 

Typically with an array like this in Javascript we’d run a for loop over the dataset and apply parse float and then round it with Math.round.

And while that is a fine approach, what if we could use composition, f(g(x)), to create a cleaner more reusable solution.

Lets start with our compose function.

var compose = function () {
  var fns = arguments;

  return function (result) {
     for (var i = fns.length - 1; i > -1; i--) {
       result = fns[i].call(this, result);
     }
     return result;
  };
};

It looks confusing but it’s actually only a few simple steps. The first being grabbing the arguments from the passed in parameters and storing it as an array.

From there we apply the usual f(g(x)). In this case the g is the parameter to the most right and the x will be what we pass into our function when we finally call it. The y is the function furthest to the left.

The for loop applies the function that is in the array of arguments that is furthest to the right to our last input, X.

Once it executes the first function it moves onto the next function with a returned result. If you’re interested in diving more into it, I would suggest putting debugger in different areas to see the values of arg or y and x.

With that basic understanding of compose we can start putting it to use. Lets take the list from above.

var dronePrices = [72.56,74.09, 100.83, 200.79, 140.7, 50.3, 56.1, 43.1, 90.8, 96.7, 114.2, 278.5]; 

var formatNumber = compose(Math.round, parseFloat); 

var formattedData = dronePrices.map(function (input) { 
    return formatNumber(input)
}); 

With this simple compose method we’ve created a piece of code that is semantically clear and reusable. We can even make it more composable by removing the anonymous function.

var anonymous = function (input) { return input };
var formatNumber = compose(anonymous,  Math.round, parseFloat); 

var formattedData = dronePrices.map(formatNumber);  
// [73, 74, 101, 201, 141, 50, 56, 43, 91, 97, 114, 279]

This is really just the beginning of what we can do with composition. Start with an impure function see if you can turn it into a pure one. If you’re feeling adventurous from there try finding a place in your code where you have two functions performing an action on a value and try some composition.

If you need a kickstart try doing this simple assignment.

This is the third piece in a series The Functional Programmer's Starter Kit. This guide details how to come from a novice to implementing functional programming into your codebase.

HD