# The Algebraic Structure of Functions, illustrated using React components

Did you know there’s an algebraic structure for functions? That may not surprise you at all. But it surprised me when I first found out about it. I knew we used functions to *build* algebraic structures. It never occurred to me that functions themselves might have an algebraic structure.

I should clarify though. When I use the word ‘function’ here, I mean function in the *functional programming* sense. Not in the *JavaScript* sense. That is, pure functions; no side effects; single input; always return a value; and so on… You know the drill. Also, I’m going to assume you understand referential transparency and composition. If not, check out A gentle introduction to functional JavaScript. It might also help if you’ve read How to deal with dirty side effects in your pure functional JavaScript.

How does this algebraic structure for functions work? Well, recall our idea of *eventual* numbers when we looked at Effect. They looked something like this:

```
const compose2 = f => g => x => f(g(x));
const increment = x => x + 1;
const double = x => x * 2;
const zero = () => 0;
const one = compose2(increment)(zero);
const two = compose2(double)(one);
const three = compose2(increment)(two);
const four = compose2(double)(two);
// ... and so on.
```

In this way we could create any integer as an *eventual* integer. And we can always get back to the ‘concrete’ value by calling the function. If we call `three()`

at some point, then we get back 3. But all that composition is a bit fancy and unnecessary. We could write our eventual values like so:

```
const zero = () => 0;
const one = () => 1;
const two = () => 2;
const three = () => 3;
const four = () => 4;
// … and so on.
```

Looking at it this way may be a little tedious, but it’s not complicated. To make a delayed integer, we take the value we want and stick it in a function. The function takes no arguments, and does nothing but return our value. And we don’t have to stop at integers. We can make any value into an *eventual* value. All we do is create a function that returns that value. For example:

```
const ponder = () => 'Curiouser and curiouser';
const pi = () => Math.PI;
const request = () => ({
protocol: 'http',
host: 'example.com',
path: '/v1/myapi',
method: 'GET'
});
// You get the idea…
```

Now, if we squint a little, that looks kind of like we’re putting a value inside a container. We’ve got a bit of containery stuff on the left, and value stuff on the right. The containery stuff is uninteresting. It’s the same every time. It’s only the return value that changes.

## Enter the functor

Could we make a Functor out of this containery eventual-value thing? To do that, we need to define a law-abiding `map()`

function. If we can, then we’ve got a valid functor on our hands.

To start, let’s look at the type signature for `map()`

. In Hindley-Milner notation, it looks something like this:

```
map :: Functor m => (a -> b) -> m a -> m b
```

This says that our map function takes a function, and a functor of `a`

, and returns a functor of `b`

. If functions are functors, then they would go into that `m`

slot:

```
map :: (a -> b) -> Function a -> Function b
```

This says that `map()`

takes a function from `a`

to `b`

and a Function of `a`

. And it returns a Function of `b`

. But what’s a ‘Function of `a`

’ or a ‘Function of `b`

’?

What if we started out with *eventual* values? They’re functions that don’t take any input. But they return a value. And that value (as we discussed), could be anything. So, if we put them in our type signature might look like so:

```
map :: (a -> b) -> (() -> a) -> (() -> b)
```

The `a`

and `b`

in the type signature are return value of the function. It’s like `map()`

doesn’t care about the input values. So let’s replace the ‘nothing’ input value with another type variable, say `t`

. This makes the signature general enough to work for any function.

```
map :: (a -> b) -> (t -> a) -> (t -> b)
```

If we prefer to work with `a`

, `b`

and `c`

, it looks like this:

```
map :: (b -> c) -> (a -> b) -> (a -> c)
```

And that type signature looks a *lot* like the signature for `compose2`

:

```
compose2 :: (b -> c) -> (a -> b) -> a -> c
```

And in fact, they are the same function. The `map()`

definition for functions *is* composition.

Let’s stick our `map()`

function in a Static-Land module and see what it looks like:

```
const Func = {
map: f => g => x => f(g(x)),
};
```

And what can we do with this? Well, no more and no less than we can do with `compose2()`

. And I assume you already know many wonderful things you can do with composition. But function composition is pretty abstract. Let’s look at some more concrete things we can do with this.

## React functional components are functions

Have you ever considered that React functional components are genuine, *bona fide* functions? (Yes, yes. Ignoring side effects and hooks for the moment). Let’s draw a couple of pictures and think about that. Functions in general, take something of type $A$ and transform it into something of type $B$.

I’m going to be a bit sloppy with types here but bear with me. React functional components are functions, but with a specific type. They take Props and return a Node. That is, they take a JavaScript object return something that React can render.^{1} So that might look something like this:

Now consider `map()`

/`compose2()`

. It takes two functions and combines them. So, we might have a function from type $B$ to $C$ and another from $A$ to $B$. We compose them together, and we get a function from $A$ to $C$. We can think of the first function as a *modifier function* that acts on the output of the second function.

Let’s stick a React functional component in there. We’re going to compose it with a modifier function. The picture then looks like this:

Our modifier function has to take a Node as its input. Otherwise, the types don’t line up. That’s fixed. But what happens if we make the return value Node as well? That is, what if our second function has the type $Node \rightarrow Node$?

We end up with a function that has the *same type as a React Function Component*. In other words, we get another component back. Now, imagine if we made a bunch of small, uncomplicated functions. And each of these little utility functions has the type $Node \rightarrow Node$. With `map()`

we can combine them with components, and get new, valid components.

Let’s make this real. Imagine we have a design system provided by some other team. We don’t get to reach into its internals and muck around. We’re stuck with the provided components as is. But with `map()`

we claw back a little more power. We can tweak the output of any component. For example, we can wrap the returned Node with some other element:

```
import React from 'react';
import AtlaskitButton from '@atlaskit/button';
// Because Atlaskit button isn't a function component,
// we convert it to one.
const Button = props => (<AtlaskitButton {...props} />);
const wrapWithDiv = node => (<div>{node}</div>);
const WrappedButton = Func.map(wrapWithDiv)(Button);
```

Or we could even generalise this a little…

```
import React from "react";
import AtlaskitButton from "@atlaskit/button";
// Because Atlaskit button isn't a function component,
// we convert it to one.
const Button = props => <AtlaskitButton {...props} />;
const wrapWith = (Wrapper, props = {}) => node => (
<Wrapper {...props}>{node}</Wrapper>
);
const WrappedButton = Func.map(
wrapWith("div", { style: { border: "solid pink 2px" } })
)(Button);
```

What else could we do? We could append another element:

```
import React from "react";
import AtlaskitButton from "@atlaskit/button";
import PremiumIcon from "@atlaskit/icon/glyph/premium";
// Because Atlaskit button isn't a function component,
// we convert it to one.
const Button = props => <AtlaskitButton {...props} />;
const appendIcon = node => (<>{node}<PremiumIcon /></>);
const PremiumButton = Func.map(appendIcon)(Button);
```

Or we could prepend an element:

```
import React from 'react';
import Badge from '@atlaskit/badge';
const prependTotal = node => (<><span>Total: </span>{node}</>)
const TotalBadge = Func.map(prependTotal)(Badge);
```

And we could do both together:

```
import React from 'react';
import StarIcon from '@atlaskit/icon/glyph/star';
import Button from '@atlaskit/button';
// Because Atlaskit button isn't a function component,
// we convert it to one.
const Button = props => <AtlaskitButton {...props} />;
const makeShiny = node => (
<>
<StarIcon label="" />{node}<StarIcon label="" />
</>
);
const ShinyButton = Func.map(makeShiny)(Button);
```

And all three at once:

```
import React from 'react';
import AtlaskitButton from "@atlaskit/button";
import Lozenge from '@atlaskit/lozenge';
import PremiumIcon from '@atlaskit/icon/glyph/premium';
import Tooltip from '@atlaskit/tooltip';
// Because Atlaskit button isn't a function component,
// we convert it to one.
const Button = props => <AtlaskitButton {...props} />;
const shinyNewThingify = node => (
<Tooltip content="New and improved!"><>
<PremiumIcon label="" />
{node}
<Lozenge appearance="new">New</Lozenge>
</></Tooltip>
);
const ShinyNewButton = Func.map(shinyNewThingify)(Button);
const App = () => (
<ShinyNewButton>Runcible Spoon</ShinyNewButton>
);
```

### Element enhancers

I call these $Node \rightarrow Node$ functions *Element enhancers*.^{2} It’s like we’re creating a template. We have a JSX structure with a node-shaped hole in it. We can make that JSX structure as deep as we like. Then, we use `Func.map()`

to compose the element enhancer with a Component. We get back a new component that eventually shoves something deep down into that slot. But this new component takes the same props as the original.

This is nothing we couldn’t already do. But what’s nice about element enhancers is their simplicity and re-usability. An element enhancer is a simple function. It doesn’t mess around with props or anything fancy. So it’s easy to understand and reason about. But when we `map()`

them, we get full-blown components. And we can chain together as many enhancers as we like with `map()`

.

I have a lot more to say about this, but I will save it for another post. Let’s move on and look at Contravariant Functors.

## Contravariant functor

Functors come in lots of flavours. The one we’re most familiar with is the *covariant* functor. That’s the one we’re talking about when we say ‘functor’ without any qualification. But there are other kinds. The contravariant functor defines a `contramap()`

function. It looks like someone took all the types for `map()`

and reversed them:

```
-- Functor general definition
map :: (a -> b) -> Functor a -> Functor b
-- Contravariant Functor general definition
contramap :: (a -> b) -> Contravariant b -> Contravariant a
-- Functor for functions
map :: (b -> c) -> (a -> b) -> (a -> c)
-- Contravariant Functor for functions
contramap :: (a -> b) -> (b -> c) -> (a -> c)
```

Don’t worry if none of that makes sense yet. Here’s how I think about it. With functions, `map()`

let us change the *output* of a function with a modifier function. But `contramap()`

lets us change the *input* of a function with a modifier function. Drawn as a diagram, it might look like so:

If we’re doing this with React components then it becomes even clearer. A regular component has type $Props \rightarrow Node$. If we stick a $Props \rightarrow Props$ function in front of it, then we get a $Props \rightarrow Node$ function back out. In other words, a new component.

So, `contramap()`

is `map()`

with the parameters switched around:

```
const Func = {
map: f => g => x => f(g(x)),
contramap: g => f => x => f(g(x)),
};
```

### Contramapping react functional components

What can we do with this? Well, we can create functions that modify props. And we can do a lot with those. We can, for example, set default props:

```
// Take a button and make its appearance default to 'primary'
import Button from '@atlaskit/button';
function defaultToPrimary(props) {
return { appearance: 'primary', ...props};
}
const PrimaryButton = Func.contramap(defaultToPrimary)(Button);
```

And, of course, we could make a generic version of this:

```
import Button from '@atlaskit/button';
function withDefaultProps(defaults) {
return props => ({...defaults, ...props});
}
const PrimaryButton = Func.contramap(
withDefaultProps({ appearance: 'primary' })
)(Button);
```

If we want to, we could also hard-code some props so that nobody can change them. To do that we reverse our spread operation.

```
import Button from '@atlaskit/button';
function withHardcodedProps(fixedProps) {
return props => ({...props, ...fixedProps});
}
const PrimaryButton = Func.contramap(
withHardcodedProps({ appearance: 'primary' })
)(Button);
```

You might be thinking, is that all? And it might not seem like much. But modifying props gives us a lot of control. For example, remember that we pass children as props. So, we can do things like wrap the *inner* part of a component with something. Say we have some CSS:

```
.spacer {
padding: 0.375rem;
}
```

And imagine we’re finding the spacing around some content too tight. With our handy tool `contramap()`

, we can add a bit of space:

```
import React from 'react';
import AtlaskitSectionMessage from '@atlaskit/section-message';
// Atlaskit's section message isn't a functional component so
// we'll convert it to one.
const SectionMessage = props => <AtlaskitSectionMessage {...props} />;
const addInnerSpace = ({children, ...props}) => ({
...props,
children: <div class="spacer">{children}</div>
});
const PaddedSectionMessage = Func.contramap(addInnerSpace)(SectionMessage);
const App = () => (
<PaddedSectionMessage title="The Lion and the Unicorn">
<p>
The Lion and the Unicorn were fighting for the crown:<br />
The Lion beat the Unicorn all round the town.<br />
Some gave them white bread, some gave them brown:<br />
Some gave them plum-cake and drummed them out of town.
</p>
</PaddedSectionMessage>
);
```

## Functions as profunctors

Our `contramap()`

function lets us change the input and `map()`

lets us change the output. Why not do both together? This pattern is common enough that it has a name: `promap()`

. And we call structures that you can `promap()`

over, *profunctors*. Here’s a sample implementation for `promap()`

:

```
const Func = {
map: f => g => x => f(g(x)),
contramap: g => f => x => f(g(x)),
promap: f => g => h => Func.contramap(f)(Func.map(g)(h)),
};
```

Here’s an example of how we might use it:

```
import React from "react";
import AtlaskitTextfield from "@atlaskit/textfield";
// Atlaskit's Textfield isn't a function component, so we
// convert it.
const Textfield = props => <AtlaskitTextfield {...props} />;
const prependLabel = (labelTxt, id) => node => (
<>
<label htmlFor={id}>{labelTxt}</label>
{node}
</>
);
function withHardcodedProps(fixedProps) {
return props => ({ ...props, ...fixedProps });
}
const id = "thamaturgical-identifier";
const lblTxt = "Please provide your thaumaturgical opinion:";
const ThaumaturgyField = Func.promap(withHardcodedProps({ id }))(
prependLabel(lblTxt, id)
)(Textfield);
export default function App() {
return (
<div className="spacer">
<ThaumaturgyField />
</div>
);
}
```

With `promap()`

we could tweak the props and the output of a React component in one pass. And this is pretty cool. But what if we wanted to change the output based on something in the input? The sad truth is that `promap()`

can’t help us here.

## Functions as applicative functors

All is not lost. We have hope. But first, why would we want to do this? Let’s imagine we have a form input. And rather than disable the input when it’s not available, we’d like to hide it entirely. That is, when the input prop `disabled`

is `true`

, then we don’t render the input at all. To do this, we’d function that has access to both the input and the output of a component. So, what if we passed the input (props) *and* output (node) as parameters? It might look like so:

```
// hideWhenDisabled :: Props -> Node -> Node
const hideWhenDisabled = props => node => (
(props.isDisabled) ? null : node
);
```

Not all that complicated. But how do we combine that with a component? We need a function that will do two things:

- Take the input (props) and pass it to the component; and then,
- Pass both the input (props) and output (node) to our
`hideWhenDisabled()`

function.

It might look something like this:

```
// mysteryCombinatorFunction :: (a -> b -> c) -> (a -> b) -> a -> c
const mysteryCombinatorFunction = f => g => x => f(x)(g(x));
```

And this mystery combinator function has a name. It’s called `ap()`

. Let’s add `ap()`

to our `Func`

module:

```
const Func = {
map: f => g => x => f(g(x)),
contramap: g => f => x => f(g(x)),
promap: f => g => h => Func.contramap(f)(Func.map(g)(h)),
ap: f => g => x => f(x)(g(x)),
};
```

Here’s how it might look as a diagram:

If we are working with react components, then it might look like so:

With that in place, we can use our `hideWhenDisabled()`

function like so:

```
import React from "react";
import AtlaskitTextfield from "@atlaskit/textfield";
// Atlaskit's Textfield isn't a function component, so we
// convert it.
const Textfield = props => <AtlaskitTextfield {...props} />;
// hideWhenDisabled :: Props -> Node -> Node
const hideWhenDisabled = props => el => (props.isDisabled ? null : el);
const DisappearingField = Func.ap(hideWhenDisabled)(Textfield);
```

Now, for a function to be a full applicative functor, there’s another function we need to implement. That’s `of()`

. It takes any value and turns it into a function. And we’ve already seen how to do that. It’s as simple as making an eventual value:

```
// Type signature for of():
// of :: Applicative f => a -> f a
// For functions this becomes:
// of :: a -> Function a
// Which is the same as:
// of :: a -> b -> a
// We don’t care what the type of b is, so we ignore it.
const of = x => () => x;
```

Let’s stick that in our module:

```
const Func = {
map: f => g => x => f(g(x)),
contramap: g => f => x => f(g(x)),
promap: f => g => h => Func.contramap(f)(Func.map(g)(h)),
ap: f => g => x => f(x)(g(x)),
of: x => () => x,
};
```

There’s not much advantage in using `Func.of()`

over creating an inline function by hand. But it allows us to meet the specification. That, in turn, means we can take advantage of derivations and pre-written code. For example, we can use `ap()`

and `of()`

to derive `map()`

:

```
const map = f => g => Func.ap(Func.of(f))(g);
```

Not all that useful, but good to know.

## Functions as monads

One final thought before we wrap up. Consider what happens if we swap the parameter order for our `hideWhenDisabled()`

function. It might look something like this:

```
// hideWhenDisabledAlt :: Node -> Props -> Node
const hideWhenDisabledAlt = el => props => (
props.isDisabled ? null : el
);
```

The inside of the function doesn’t change at all. But notice what happens if we partially apply the first parameter now:

```
import TextField from '@atlaskit/textfield';
// hideWhenDisabledAlt :: Node -> Props -> Node
const hideWhenDisabledAlt = el => props => (
props.isDisabled ? null : el
);
const newThing = hideWhenDisabled(<TextField name="myinput" id="myinput" />);
```

What’s the *type* of `newThing`

?

That’s right. Since we’ve filled that first Node slot, the type of `newThing`

is $Props \rightarrow Node$. The same type as a component. We’ve created a new component that takes just one prop: `isDisabled`

. So, we can say that `hideWhenDisabledAlt()`

is a function that takes a Node and returns a Component.

That’s pretty cool all by itself. But we can take this one step further. What if we could chain together functions like this that returned components? We already have `map()`

which lets us shove a Component into an element enhancer. What if we could do a similar thing and jam components into functions that return components?

As it so happens, this is what the monad definition for functions does. We define a `chain()`

function like so:

```
// Type signature for chain in general:
// chain :: Monad m => (b -> m c) -> m b -> m c
// Type signature for chain for functions:
// chain :: (b -> Function c) -> Function b -> Function c
// Which becomes:
// chain :: (b -> a -> c) -> (a -> b) -> a -> c
const chain = f => g => x => f(g(x))(x);
```

Drawn as a diagram, it might look something like this:

And here’s how it looks inside our `Func`

module:

```
const Func = {
map: f => g => x => f(g(x)),
contramap: g => f => x => f(g(x)),
promap: f => g => h => Func.contramap(f)(Func.map(g)(h)),
ap: f => g => x => f(x)(g(x)),
of: x => () => x,
chain: f => g => x => f(g(x))(x),
flatMap: Func.chain,
};
```

I like to add `flatMap()`

as an alias to `chain()`

. Naming it `flatMap()`

makes more sense and is contsistent with `Array.prototype.flatMap()`

. But, `chain()`

is what we have in the specification. And, to be fair, Brian wrote the Fantasy Land spec before `flatMap()`

for arrays existed.

If we substitute the component type into our diagram above, then it looks like so:

What can we do with `chain()`

/`flatMap()`

? We can take a bunch of functions that return components and chain them together. For example:

```
import Modal, { ModalTransition } from '@atlaskit/modal-dialog';
// compose :: ((a -> b), (b -> c), ..., (y -> z)) -> a -> z
const compose = (...fns) => (...args) =>
fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
const wrapInModal = inner => ({ onClose, actions, heading }) => (
<Modal actions={actions} onClose={onClose} heading={heading}>
{inner}
</Modal>
);
const showIfOpen = inner => ({ isOpen }) => isOpen && <>{inner}</>;
const withModalTransition = el => <ModalTransition>{el}</ModalTransition>;
const modalify = compose(
Func.map(withModalTransition),
Func.chain(showIfOpen),
Func.chain(wrapInModal),
);
```

We now have a function `modalify()`

, that will take any *Component* and place it inside a modal. Not any *Element* or *Node*. No, any *Component*. As a consequence, our new ‘modalified’ component will take four extra props. They are `actions`

, `isOpen`

, `onClose`

and `heading`

. These control the appearance of the modal. But, the way it’s written now, it will pass those to the inner component too. We can prevent that with a prop modifier:

```
const withoutModalProps = ({ actions, isOpen, onClose, heading, ...props }) =>
props;
const modalify = compose(
Func.map(withModalTransition),
Func.chain(showIfOpen),
Func.chain(wrapInModal),
Func.contramap(withoutModalProps),
);
```

Now, this perhaps isn’t the best example. It will probably be more *familiar* to most people if we write this out using JSX:

```
const modalify = Component => ({actions, isOpen, onClose, heading, ...props}) => (
<ModalTransition>
{isOpen && (
<Modal actions={actions} onClose={onClose} heading={heading}>
<Component {...props} />
</Modal>
)}
</ModalTransition>
);
```

## But why?

Let me ask you a question. We have two versions of the same `modalify()`

function above. One written with composition, the other with plain JSX. Which is more reusable?

It’s a trick question. The answer is neither. They’re the same function. Who cares whether it’s written with composition or JSX? As long as their performance is roughly the same, it doesn’t matter. The important thing is that we can write this function *at all*. Perhaps you are more clever than I am. But it never would have occurred to me to write a `modalify()`

function before this. Working through the algebraic structure opens up new ways of thinking.

Now, someone might be thinking: “But this is just higher-order components (HOCs). We’ve had those for ages.” And you’d be correct. The React community has been using HOCs for ages. I’m not claiming to introduce anything new here. All I’m suggesting is that this algebraic structure might provide a different perspective.

Most HOCs tend to be similar to our `modalify()`

example. They take a component, modify it, and give you back a new component. But the algebraic structure helps us enumerate all the options. We can:

- Modify Nodes (elements) returned from a Component with
`map()`

; - Modify Props going into a Component with
`contramap()`

; - Do both at the same time with
`promap()`

; - Modify Nodes based on values in Props with
`ap()`

; and - Chain together functions that take a Node and return a Component with
`chain()`

(aka`flatMap()`

).

And no, we don’t *need* `promap()`

or `ap()`

or `chain()`

to do any of these things. But when we do *reuse* in React, we tend to think *only* of Components. *Everything is a component* is the mantra. And that’s fine. But it can also be limiting. Functional programming offers us so many ways of combining functions. Perhaps we could consider reusing functions as well.

Let me be clear. I’m not suggesting anyone go and write all their React components using `compose`

, `map()`

, and `chain()`

. I’m not even suggesting anyone include a `Func`

library in their codebase. What I am hoping is that this gives you some tools to think differently about your React code. I’m also hoping that the algebraic structure of functions makes a little more sense now. This structure is the basis for things like the Reader monad and the State monad. And they’re well worth learning more about.