Forever Functional: Higher Order Functions -- Functions to rule functions
Tags: functional, javascript, tutorial
Published: 2021-09-13 05:26:42

_by author [Federico Kereki](https://blog.openreplay.com/authors/federico-kereki)_

Common features in functional programming (FP) include passing functions around as parameters to other functions, and returning new functions as a result! In a strict theoretical sense, a Higher Order Function (HOF) takes one or more functions as arguments, and possibly also returns a function as a result.

In this article, we're interested in HOFs that return new functions. We may classify such HOFs into three groups:

* **Functionality-wrapping**: the original functionality is kept, but some new feature is added. We saw prime examples of this in our articles on [memoizing functions](https://LINK_TO_THE_MEMOIZING_FUNCTIONS_ARTICLE) and [memoizing promises](https://LINK_TO_THE_MEMOIZING_FUNCTIONS_ARTICLE). In both cases, the produced functions did the same work but more efficiently thanks to caching. Other examples of wrapping could be *timing* (getting time performance data) or *logging* (generating logs), and we'll see those below.

* **Functionality-altering**: the original functionality is modified in some way. For example, we might have a boolean function that tests for a condition, and alter it to negate (invert) its result. Another case: we may fix the arity of a function to avoid problems that we saw in our article on [Pointfree programming](https://LINK_TO_THE_POINTFREE_PROGRAMMING_ARTICLE); these are the examples we'll look at.

* **Functionality-creating**: these HOFs provide new functions of their own. As an example, we might decouple methods from objects to use them as common functions, or transform a function that works with callbacks into a promise for neater handling; we'll get into those.

Let's see examples of these transformations, so you can get an idea of the many possible usages for HOFs! The examples in this text are based on code from my [Mastering JavaScript Functional Programming](https://www.packtpub.com/product/mastering-javascript-functional-programming/9781787287440) book, in which you will find several more examples of HOFs.

## Wrapping the original functionality

Wrapping a function implies producing a new version with the exact same functionality as the original one, adding some interesting side effects.

### Timing functions

Let's suppose we want to measure the performance of a function. We could modify the function to get the current time at the beginning and just before returning, but with a HOF we don't need that. We will write an `addTiming(...)` function that will return a new function that will log timing data in addition to doing whatever it would normally do.

```javascript
const addTiming = (fn) => (...args) => {
  let start = performance.now();   /* [1] */
  try {
    const toReturn = fn(...args);  /* [2] */
    console.log("Normal exit", fn.name, performance.now()-start, "ms");
    return toReturn;
  } catch (thrownError) {          /* [3] */
    console.log("Exception thrown", fn.name, performance.now()-start, "ms");
    throw thrownError;
  }
};
```

The function that we'll return starts ([1]) by getting the initial time using [performance.now()](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) for better accuracy. Then it calls the original function ([2]) and if there's no problem it logs "Normal exit", the function name, and the time it took. If the function threw an exception ([3]) it logs "Exception thrown" plus the function name and the total time, and throws the same error again, for further process. Let's see an example.

```javascript
function add3(x, y, z) {
  for (let i = 1; i < 100000; i++);
  return x + y + z;
}

add3 = addTiming(add3); /* [1] */

add3(22,9,60);          /* [2] */
// logs: Normal exit add3 3.200000047683716 ms
// returns: 91 
```

We change our original function for a new version that includes timing ([1]). When we call this new function ([2]) we get some logging in the console, and the returned value is whatever the original function calculated... With a HOF we can now time any function without modifying it!

### Logging functions

Another common example of wrapping is adding a logging feature. A so modified function will let you see in the console output when it is called, with which arguments, and what it returns. As with timing, we don't want to modify the original function -- that's error-prone, and not a good practice!

Similarly to what we did in the previous section, we'll write an `addLogging(...)` function that will take a function as a parameter and return a new function that will start by logging its arguments, then call the original function, log whatever it returned, and finally return that value to the caller. We will also take exceptions into account. A possible implementation could be the following.

```javascript
const addLogging =
  (fn) =>
  (...args) => {                                  /* [1] */
    console.log("Enter", fn.name, ...args);
    try {
      const toReturn = fn(...args);               /* [2] */ 
      console.log("Exit ", fn.name, toReturn);    
      return toReturn;
    } catch (err) {
      console.log("Error", fn.name, err);         /* [3] */
      throw err;                                  
    }
  };
```

We start ([1]) by logging the arguments of the function. Then ([2]) we call the original function and store its result. If there's no problem we just log "Exit" and the result, and we return to the caller. If there's some error, we log "Error" and the exception, and we throw the latter again.

We can use the function simply; let's re-use the example from the previous section.

```javascript
function add3(x, y, z) {    // same as avoe
  for (let i = 1; i < 100000; i++);
  return x + y + z;
}

add3 = addTiming(add3);     /* [1] */

addLogging(add3)(22,9,60);  /* [2] */
// logs: Enter add3 22 9 60
// logs: Exit  add3 91
// returns: 91
```

We produce a new function ([1]) that will do its logging, and when we call it ([2]) we get extra output.  By the way, you could add both logging and timing, with something like `addTiming(addLogging(add3))` -- can you see how it would work?

## Altering the original functionality

In this second category of changes, we'll see two simple situations: reversing a boolean decision to gain flexibility in functions like filtering, and changing the arity of functions to solve a problem with functions that expect optional parameters.

## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue. 
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).

## Negating a condition

Suppose you have written a function to test for some condition. For instance, you could have a function to filter accounts according to some internal criteria. With that function, you may write code as follows.

```javascript
const goodAccounts = listOfAccounts.filter(isGoodAccount);
```

This code uses the `isGoodAccount(...)` function to extract good accounts from a given list. Now, what would you do if you needed to extract the *bad* accounts instead? You could certainly write something like this, but it doesn't look as clean -- at least in the pointfree style that we've been using.

```javascript
const badAccounts = listOfAccounts(v => !isGoodAccount(v));
```

We can get a better solution by using a HOF that will invert (negate) whatever a given function produces. We can write this HOF in just a single line, as follows.

```javascript
const not = fn => (...args) => !fn(...args);
```

Given a function as an argument, `not(...)` produces a new function that will invoke the original, and then negate whatever it returned. With this, you can now write very directly the following.

```javascript
const badAccounts = listOfAccounts(not(isGoodAccount));
```

Now the code is as legible as the one to filter the good accounts; a win! You can extend the idea here to allow joining several conditions with boolean operators: for example, you may write `and(...)` and `or(...)` HOFs that would let you write something like this.

```javascript
const goodInternationalAccounts = listOfAccounts.filter(and(isGoodAccount, isInternationalAccount));
```

And, of course, you could mix things up!

```javascript
const badInternationalAccounts = listOfAccounts.filter(and(not(isGoodAccount), isInternationalAccount));
```

I'll leave these boolean HOF functions up to you, a nice exercise!


## Changing the arity of functions

In our [article on pointfree style](https://LINK_AL_ARTICULO_DE_POINTFREE_PROGRAMMING) we saw a problem.

```javascript
const numbers = [22,9,60,12,4,56];
numbers.map(Number.parseFloat); // [22, 9, 60, 12, 4, 56]
numbers.map(Number.parseInt);   // [22, NaN, NaN, 5, NaN, NaN]
```

Why did the second map(...) produce such weird results? The reason is that `parseInt(...)` allows for a second (optional) argument, but `parseFloat(...)` doesn't. In technical terms, the arity of these functions is 2 and 1 respectively. We can transform the former function into a unary (arity 1) function very simply by using a HOF.

```javascript
const unary = fn => (arg0, ...args) => fn(arg0);
```

Given an `fn` function, `unary(fn)` produces a new function that, given several arguments, calls `fn` with just the first, discarding the rest. With this, our problem is easily solved in a different way than what we saw in our previous article.

```javascript
numbers.map(unary(Number.parseInt));   // [22, 9, 60, 12, 4, 56]
```

In the same way that we transformed a function into a unary one, it would be simple to write `binary(...)`, `ternary(...)`, and more functions to transform functions to arity 2, 3, etc.; we'll leave this as another exercise!


## Creating new functionality

We'll see a couple of examples: we'll transform methods into functions, and callback-using functions into promises.

### From methods to functions

Some methods (like `map(...)`, say) are available for arrays, but if you wanted to use them elsewhere you'd be out of luck. We can, however, write a HOF that will convert any method into an equivalent function. Instead of `object.method(args)` you would write `method(object,args)` -- and now you got a function that you can pass around in true FP style!

How can we manage this? The [bind(...)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) method is key, and a possibility is as follows.

```javascript
const demethodize = fn => (...args) => fn.bind(...args)();
```

(By the way, there are more ways to implement `demethodize(...)`, for instance using [apply(...)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) or [call(...)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) -- if you're up for a challenge, try to do this!)

Let's say you wanted to be able to use the [.toUpperCase(...)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) method as a function. You'd write the following.

```javascript
const toUpperCase = demethodize(String.prototype.toUpperCase);
console.log(toUpperCase("this works!"));
// THIS WORKS!
```

FP is more geared to functions than to methods, so being able to transform methods into functions helps you work in a better fashion.

### From callbacks to promises

Let's go with an example from Node. In it, by definition all async functions require an ["error first" callback](https://nodejs.org/api/errors.html#errors_error_first_callbacks) such as `(err, data) => { ... }`. If `err` is null, the operation is assumed to have succeeded and `data` has its result; otherwise, `err` gives the cause for the error. However, we could prefer working with promises instead. We can write a HOF that will transform an async function that requires a callback into a promise that lets you use `.then/.catch` or `await`. (OK, Node already provides [util.promisify()](https://nodejs.org/api/util.html#util_util_promisify_original) to do exactly this -- but let's see on our own how we'd go about it.) The needed transformation is not hard.

Given any function, we'll return a new one that will return a function. After calling the original function, the promise will be resolved or rejected depending on what was returned. We can write this quickly.

```javascript
const promisify = fn => (...args) =>
  new Promise((resolve, reject) =>
    fn(...args, (err, data) => (err ? reject(err) : resolve(data)))
  );
```

Now, how would we read a file in Node with the `fs.readFile(...)` function? (Yes, Node also provides a [fs/promises API](https://nodejs.org/api/fs.html#fs_promises_api) that already returns promises. In actual production, we'd use that instead of promisifying things by ourselves.) We could do the following.

```javascript
const ourRead = promisify((...args) => fs.readFile(...args));

ourRead("some_file.txt")
  .then(data => /* do something with data */)
  .catch(err => /* process error err */);
  
// or equivalently

try {
  data = await ourRead("some_file.txt");
  /* do something with data */
} catch (err) {
  /* process error err */
}
```

Nice and easy! 

## Summary

In this article we have explored the concept of Higher Order Functions (HOF), a common feature in Functional Programming, and we've seen several examples of their usage to cover common, everyday needs in development. Getting used to HOFs will give you much leeway in writer shorter, clearer, and more efficient code; try to practice using them!