Function composition and higher-order function
Tags: functional, programming, tutorial, typescript
Published: 2021-09-16 16:32:36

## Table of contents

- [Function composition](#function-composition)
- [How far we can go with it](#how-far-we-can-go-with-it)
- [Higher-order function](#higherorder-function)

---

## Function composition

Function composition is a simple yet powerful key concept in Functional Programming.

### What is it?

In a nutshell, it's the ability to combine behaviors together in a specific order, transforming data little by little from an initial _shape_ into a new one.

More concretely, it's the combination of functions where the output (returned value) of the previous function becomes the input (argument) of the next one, and so on until the last function.

We can visualize it as a pipeline where some data of a given _shape_ enters on one side, then comes out with a new (same or different) _shape_ on the other side.

![A blue square goes inside an opaque pipe on one side, then comes out as a purple hexagon on the other side](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ortpdv1qk43j3v0paxr.png)

Composing functions yields... Another function! Therefore a pipeline is, in turn, a function. We don't know exactly how it's defined from an external point of view, and that's why it's so powerful: **it's an abstraction that hides implementation details**. The intermediate steps to transform a `BlueSquare` into a `PurpleHexagon` are hidden/abstracted.

Given the following 3 functions `f`, `g`, and `h`:

![3 functions are defined: "f" as blue square to green circle, "g" as green circle to red diamond, then "h" as red diamond to purple hexagon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2p6x5wsq1owahwvca9x.png)

Can we compose these functions to create the pipeline from above? Let's see:
- `f` takes a `BlueSquare` as input, then returns a `GreenCircle`
- `g` takes a `GreenCircle` as input (therefore, it can be composed with `f`, if `f` comes first), then returns a `RedDiamond`
- `h` takes a `RedDiamond` as input (therefore, it can be composed with `g`, if `g` comes first), then returns a `PurpleHexagon`

By aligning `f`, then `g` and finally `h`, we end up with a pipeline that takes a `BlueSquare` as input, and returns a `PurpleHexagon`, which is exactly what we were looking for!

![Composition of the 3 functions "f", "g" and "h" illustrated, ending up with a final function "h round g round f", taking a blue square as input and returning a purple hexagon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xznkhlvph2h2o37zr4ot.png)

> The weird notation with circles is the way [function composition in mathematics](https://en.wikipedia.org/wiki/Function_composition) is written: `h ∘ g ∘ f` can be read as "h round g round f", and is applied from right to left: `h(g(f(x)))`.

### How far we can go with it

Since pipelines are functions, it means we can compose them with other functions as well. This is the **essence** of software programming: composing smaller pieces together to end up with a complex system that fulfills all the requirements.

Suppose we need to transform some `GreenCircle` into a `PurpleHexagon` somewhere in our code base. Do we have to implement this function by ourselves, or can we simply compose functions that already exist?

![Can we compose the functions defined earlier to come up with a new function that takes a green circle as input, and returns a purple hexagon?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bo4wm4rwd2kprspomk61.png)

> Here, we are assuming the actual implementations of the functions from above suit our needs. In reality, there could be several implementations for a function transforming a `GreenCircle` into a `PurpleHexagon`. For example, `isEven` and `isOdd` are both functions that transform numbers (green circles) into booleans (purple hexagons), but with different implementations.

Of course we can, by composing `g` with `h`:

![The composition of "g" and "h" functions yields a function that takes a green circle as input, and returns a purple hexagon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5pywjif7tzr0p2igunem.png)

And since this pipeline is a function, we can actually define the previous pipeline using this one and `f`:

![The composition of the function "g" with the pipeline "h round g" yields the pipeline "(h round g) round f", which is the same pipeline as the first example, but with the reusable "h round g" that we just defined](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0wh8r82q4lcmhmmkfk3.png)

This way, we have reusable units/functions in our code base that can be composed anywhere to form new functions/pipelines that are more and more complex.

Shapes are nice, but if you're looking for something more concrete, here's an example with simple functions in TypeScript:

```ts
const getNumberOfCharacters =
  (text: string): number => text.length

const increment = 
  (n: number): number => n + 1

const isGreaterThan5 =
  (n: number): boolean => n > 5

// pipeline definition
const isTextLongEnough: (text: string) => boolean =
  flow(getNumberOfCharacters, increment, isGreaterThan5)

console.log(isTextLongEnough('abc')) // false
console.log(isTextLongEnough('abcde')) // true
```

I'm using the `flow` function from the [fp-ts](https://github.com/gcanti/fp-ts) library, which is used specifically to compose functions, from left to right. I could've written it the following way, but it's less readable in my opinion:

```ts
const isTextLongEnough: (text: string) => boolean =
  text => isGreaterThan5(increment(getNumberOfCharacters(text)))
```

The advantage of having small units/functions is that we can reuse some of them to create different pipelines. For example:

```ts
const isEven =
  (n: number): boolean => n % 2 === 0

const hasEvenNumberOfCharacters: (text: string) => boolean =
  flow(getNumberOfCharacters, isEven)

console.log(hasEvenNumberOfCharacters('abc')) // false
console.log(hasEvenNumberOfCharacters('abcd')) // true
```

Wait a minute... All these functions have only 1 argument, also called _unary functions_. What happens if we want to compose functions that take multiple arguments? For example:

![Function that takes 3 arguments (in the order: yellow star, green circle, and cyan diamond) and returns a red diamond](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4d2winwid0haat7s7uwb.png)

Or more concretely:

```ts
const isGreaterThan =
  (n: number, limit: number): boolean => n > limit
```

The answer lies in **currying** and **partial application**, which are 2 concepts we'll see later in this series. Stay tuned!

## Higher-order function

A higher-order function, or HOF for short, is a function that takes at least a function as its argument(s), and/or returns a new function.

If you have used the `map` and `filter` methods on an array in JavaScript, then you have already used HOFs, because these 2 methods take a function as their arguments:

```ts
const evenNumbers = [1, 2, 3, 4].filter(n => n % 2 === 0)
// or the shorter version: [1, 2, 3, 4].filter(isEven)

console.log(evenNumbers) // [2, 4]

const doubledNumbers = [1, 2, 3].map(n => n * 2)

console.log(doubledNumbers) // [2, 4, 6]
```

We can create our own higher-order functions as well. Let's have a look at a simple example, in TypeScript and Scala:

```ts
const enum Shape {
  BlueSquare,
  GreenCircle,
  RedDiamond
}

function createShapes(
  volume: number,
  generateShape: () => Shape
): Shape[] {
  return [...new Array(volume)].map(() => generateShape())
}
```

```scala
sealed trait Shape
case object BlueSquare extends Shape
case object GreenCircle extends Shape
case object RedDiamond extends Shape

def createShapes(
  volume:        Int,
  generateShape: () => Shape
): List[Shape] =
  List.range(0, volume).map(_ => generateShape())
```

Here the `createShapes` function is a HOF, because it takes a function as one of its arguments: `generateShape`.

If you are familiar with design patterns from Object-Oriented Programming, then you might have thought about the _Strategy pattern_ here, and you would've been correct. In fact, a lot of OO design patterns can be implemented using HOFs. That being said, some of the OO patterns don't make sense in FP, since we are not trying to solve problems with classes and objects, but rather with data and functions.

> The `flow` function that we saw earlier is also a HOF, since it takes multiple functions as its arguments, and returns a function at the end.

We can define a higher-order function in TypeScript to emulate some form of _pattern matching_ on these shapes:

```ts
function matchShape(
  onBlueSquare:  (shape: BlueSquare) => void,
  onGreenCircle: (shape: GreenCircle) => void,
  onRedDiamond:  (shape: RedDiamond) => void
) {
  return (shape: Shape): void => {
    switch (shape) {
      case BlueSquare:
        return onBlueSquare(shape)
      case GreenCircle:
        return onGreenCircle(shape)
      case RedDiamond:
        return onRedDiamond(shape)
    }
  }
}

matchShape(
  shape => console.log('Blue is my favorite color!', shape),
  shape => console.log('I love green tea!', shape),
  shape => console.log('I have a red car!', shape)
)(GreenCircle)
```

In this example, `matchShape` is a HOF as it takes 3 arguments that are functions, and returns a new function that takes a `Shape` as its argument.

If you are from the web app development world, you might have crossed path with [Higher-Order Components](https://reactjs.org/docs/higher-order-components.html), or HOCs. In React, a HOC is a function that takes a component as its argument, and returns a new component. We can clearly see the similarities with HOFs here.

---

Alright, we've reached the end of this chapter.

**Summary**
- Function composition is the ability to combine functions together, in a specific order, to transform some shape into a new shape.
- A higher-order function, or HOF, is a function that takes at least 1 function as its argument(s), and may return a new function.

Thank you for reading this far! I hope everything was clear and you learned something. If you have any question or need some clarifications, feel free to leave a comment :) 

The next article in this series will be about "declarative vs imperative" programming. See you next time!

---

Photo by <a href="https://unsplash.com/@xavi_cabrera?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Xavi Cabrera</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>.

Pictures created with [Excalidraw](https://excalidraw.com/).