In this three-part series, I want to take a functional approach to building React applications.

There will be mathematical theory sprinkled throughout the series, and hopefully by the end of it you will pick up some useful techniques!

**Series contents:**

- Part 1 - Deconstructing the React Component
- Part 2 - The Reader monad and read-only context
- Part 3 - Functional state management with Reducer

Functional programming – category theory in particular – teaches us a lot about program construction.
Much of the tools that functional programmers reach for are very generalized, and widely applicable to
various domains. It is this *learn once, appy everywhere* idea that I think would appeal to many folks
in the business of making software. (Not to mention that functional programming is fun!)

React has many patterns that grew out of the community. I want to take a step back and view these patterns from a new angle, and see if we can formalize them with mathematical theory.

You will need basic React knowledge in order to understand this series. I will discuss concepts such as components, elements, and higher-order components (HOC).

If you want to jump ahead a bit, the repository with the final, full examples are on GitHub. Word of warning though, there isn’t much documentation, so it’s probably easier to read the posts. ;)

So let’s get started!

## React from first principles

An **element** in React describes what should be rendered in the UI.

These elements are **immutable** since you cannot modify them after they are created. So what can you do
with immutable elements? Pass them to functions of course!

Let’s look at three **pure** functions that take in an element and outputs another element. We say that these functions
are pure because they do not have any observable side-effects – just *data in*, and *data out*.

**A bit of theory:**
The type for an element is `React.Element`

, which are *objects* in category theory.
Other examples of objects are `String`

, `Boolean`

, etc.

The pure functions `uppercase`

, `clap`

,
and `emphasize`

are *morphisms* in category theory. A morphism is a mapping between two objects --
in this case `React.Element -> React.Element`

.

We can also create computations that allows us to capture data in our elements.

Nothing fancy here. Just a plain old *functional component* in React. You could render it
via JSX `<Greeting name="Alice"/>`

, but I prefer to treat it as a normal function for now
– `Greet({ name: 'Alice' })`

.

Now we’re ready for our first contrived example!

This will render “*👏 HELLO ALICE! 👏*” on the screen.

The function `contrivedEx`

has two responsibilities:

**Run**the computation`Greeting`

to get an element out.**Map**the resulting element through multiple functions, then returning the final result.

Let’s formalize these two concepts.

## Look at my shiny new box!

We can wrap the original `Greeting`

computation in a box, which I will call **View**.

To get the value out of the box, we just need to *fold* it.

As you can see, the `fold`

function let’s us extract the value out of the box.

Hmm, but now when we want to map over our elements, we have to keep folding it down.

This is very tedious, so let’s define a mapping function that can operate on the values within our boxes.

The `map`

function will return a brand-new box that runs the original computation
through the provided function `f`

. Note that `map`

is pure a function, and we
can still maintain a reference to the original box.

All **computations are delayed** until we call the `fold`

function. This is a really useful property since we
can perform multiple transformations without needing to work with concrete values.

We can visualize `map`

as follows.

The morphisms can operate on values (elements), or we can bring them into the world of boxes (Views) and map from box to box. You can extract an element at any point by folding it down, but now we don’t have to until we really need it!

**A bit of theory:**
The View box that we just create is called a *Functor* in category theory. You can think of
functors as any object that provides the `map`

function.

There are two mathematical laws that functors must obey:

- Identity:
`a.map(x => x) === a`

- Composition:
`a.map(x => f(g(x)) === a.map(g).map(f)`

We can use these laws to our advantage when composing applications. For example,
our previous `superGreeting`

view can be optimized by calling `map`

only once, using the composition `compose(clap, emphasize, uppercase)`

.

Because of the composition law, we know that `Greeting.map(uppercase).map(emphasize).map(clap)`

is identical to `Greeting.map(compose(clap, emphasize, uppercase))`

.

While we’re at it, let’s also make the View a *Pointed Functor* by allowing us to make a *single value* into
a View using the `View.of`

function.

A quick aside on `compose`

. I’m using a library called Ramda that provides a lot of
utilities for functional programming, include `compose`

. The composition is applied from right-to-left,
so `f(g(x))`

is the same as `compose(f, g)(x)`

. The mathematical symbol “∘” also denotes a composition –
.e.g. `f ∘ g === compose(f, g)`

.

Okay, moving on!

## Formalizing higher-order component concepts

So, isn’t the `View`

box kind of like higher-order components (HOC)? Which we already have in “normal” React.

Here, we have two functions that when given a component or view, returns something that is like the original input, but in red.

The difference between the HOC and the View is that the latter formalizes the concept of
mapping its value through the `map`

function.

But wait, there is something that HOCs can do that Views cannot (yet).

For example,

The `withColor`

HOC takes a color (e.g. `red`

, `#fff`

, `rgb(0,0,0)`

, etc.), *then* a component
that uses the `color`

prop, and *then* returns a component that is the original, but with the
`color`

prop already provided.

Whereas the `red`

HOC is mapping over the resulting *value*, the `withColor`

HOC is mapping
over the *input* props. And since `view.map`

maps over the value (element), there is no chance for us
to map over the original input to a view’s computation.

So is there anything we can do?

Of course! We just need to formalize this new concept.

## Mapping over inputs

Remember that the View wraps a computation defined as `Props -> Element`

. Let’s take a look
at a concrete example with our previous color computation.

Here, we have `Props`

that is some data that contains color, and `Element`

is the
resulting `<span>`

based on the color passed in.

What we want to do now, is to map over the input props before passing them into the computation.
This can be done by defining a nifty new function called `contramap`

.

Note that with `map`

we call `f`

with the resulting value, but with `contramap`

we call `g`

with the input props, and then *that* result is passed to the computation as input.

So, with our new function, we can do the following.

Awesome! We can now map over results and contramap over inputs!

**A bit of theory:**
The View is now also a *Contravariant*, in addition to being a functor. You can think of
contravariants as any object that provides the `contramap`

function.

And just like functors, contravariants also have similar mathematical laws:

- Identity:
`a.contramap(x => x) === a`

- Composition:
`a.contramap(x => f(g(x)) === a.contramap(f).contramap(g)`

The main difference between `map`

and `contramap`

is that composition
with the latter is reversed. We can visualize the difference with these two pictures

**Functor composition**

**Contravariant composition**

### No need for HOCs

Now that we’ve captured both `map`

and `contramap`

use cases of HOCs, we no longer need them! We only need to consider
whether we are mapping over result or input to decide whether we want `map`

or `contramap`

.

By formalizing these concepts we can be more explicit and precise about *what* we are mapping over, and *how* we are mapping.
Additionally, we have mathematical laws to help us compose our program, which is awesome!

## Quick Recap

So far we’ve seen how we can:

- Put a computation of the form
`Props -> Element`

into a box (View). - Take the value out via
`fold`

. - Map over the resulting element via
`map`

. - Map over the input props via
`contramap`

.

But what if we want to combine multiple Views together?

## Combining multiple boxes

Let’s step back from the world of React for a bit and consider an array.

We can see that arrays are functors since they implement a `map`

function that
obeys the functor laws – you can verify this for yourself!

But arrays have something our View does not: a way to combine two arrays into a new array.

So let’s add this `concat`

function to our View.

**A bit of theory:**
The View is now also a *Semigroup*, which are objects that provide the `concat`

function.

Semigroups have one law:

- Associativity:
`(a.concat(b)).concat(c) === a.concat(b.concat(c))`

Note, that View doesn't *technically* obey the associativity law since the ordering of the nested `div`

s are different.
We will correct this later on in this post, but for now let's say that `concat`

ordering is not affecting how the combined View *appears* on the screen.

And now we can `concat`

like a boss!

Yes, the `map`

and `contramap`

are a bit gratuitous… But, if you run the program, you should see this.

## Let’s fix the associativity problem for semigroup

Remember that our View currently doesn’t obey associativity, because `(a.concat(b)).concat(c)`

will not
generate the same markup as `a.concat(b.concat(c))`

.

For example:

We can fix this by making sure that the computation results in something that’s already a semigroup. In this case, we can use an array.

Let’s define a function that will adapt the result as an array if it isn’t one already.

Now, we can compose the View with the new `asArray`

function, thus guaranteeing that the computation
always results in an array.

We also have to modify our previously defined functions slightly to work with an array rather than a single value.

Indeed, we can verify that the associativity law now holds.

Just for fun, we can also make View a *Monoid* by providing an `empty`

function.

**A bit of theory:**
The View is now a *Monoid*, and it provides the `View.empty`

function that has the
following laws.

- Right identity:
`a.concat(A.empty()) === a`

- Left identity:
`A.empty().concat(a) === a`

Remember how we filtered out `null`

values that result from the computation? This is why the right
and left identity laws hold. Otherwise, React will generate HTML comments for `null`

children, thus resulting
in different markup.

## Summary

Phew! I think this is a good stopping point for this post. Let’s see what we’ve done so far.

- We added a new “box” called View that holds a computation to generate a React element.
- We added a
`fold`

function that extracts a value out of the box. - We added a
`map`

function that maps over the value in the box. - We added a
`contramap`

function that maps over the input in the box. - We added a
`concat`

function that combines two boxes together.

And along the way we learned about **Functors**, **Contravariants**, **Semigroups**, and **Monoids**.

But we are not done yet since our View still hasn’t recreated two key features of React components:
*context* and *state*.

In the next post, we will replicate the React context using the Reader monad.

For more resources on related functional programming topics, I recommend the following:

- Functional Programming Jargon
- Functors, Applicatives, And Monads In Pictures by Aditya Bhargava
- Oh Composable World! (video) by Brian Lonsdorf
- Professor Frisby Introduces Composable Functional JavaScript (course) by Brian Lonsdorf
- Brian Lonsdorf on Medium and Twitter