# Type-safe monads and React

## a match made in heaven

### Introduction

In this article I will briefly introduce the concept of monad, discuss a new framework, monadic react, that encapsulates React inside a powerful monadic interface written in TypeScript, and then I will give a couple of examples of how to use this all in practice, and how powerful it proves to be.

### Yet another introduction to monads

Monads are generic datatypes respecting a certain interface that encodes a given degree of “expressive power” of this datatype. There are many definitions of this interface, and they are all equivalent. The crucial aspect of a monad is that it can be:

- created
- transformed
- flattened

Since we said that at the core of a monad is a generic datatype, let us make an example of such a generic datatype:

type Option<A> = { kind:"none" } | { kind:"some", v:A }

The monad in this case will be just `Option`

, without a specific argument. `Option`

is a function from types to types: we pass it a type such as `number`

or `boolean`

(the `< >`

brackets are suggestive in this regard) and `Option`

gives us back the nullable definition of that type.

By substitution it is indeed easy to see that, according to the above definition of `Option`

,

Option<number> = { kind:"none" } | { kind:"some", v:number }

is the return value of invoking `Option`

with `number`

as argument.

In general though, for a monad what we need is a generic type, which we shall call `M`

.

Since we have no intention of knowing *too much *about `M`

, we need to know how to construct an instance of `M<A>`

from a simple object of type `A `

which will become the payload of the constructed `M<A>`

. This is a sort of external constructor, which in the design pattern literature would be called a *factory*, but in the monadic world is called *unit* (since it is the simplest non-empty instance of `M`

we can think of, thus a sort of “one”).

The declaration of `unit`

will therefore look like:

let unit = <A>(x:A) : M<A> => ...

A simple implementation for `unit`

in the context of `Option`

would become:

let unit = <A>(x:A) : Option<A> => ({ kind:"some", v:x })

that simply encapsulates the value `x`

inside an `Option`

container. Notice that not all definitions of `M`

will be containers in the strict sense of `Option`

, `List`

, or `Array`

, so the idea of `x`

becoming the *content *of `M<A>`

is a bit of a simplification, but bear with me for the moment.

The monad must be transformable, meaning that if we have an instance of a monad and a function that can process its input, then we want be able to transform the content of the monad and directly re-encapsulate it inside a new instance of a new monad. This is commonly known as `map`

. In the last years we have seen this concept arise in many mainstream programming languages, as many generic collection libraries now feature the `map`

function to transform a whole collection element-by-element.

One possible declaration of `map`

is as follows:

let map = <A,B>(p:M<A>, f:(_:A)=>B) : M<B> => ...

`map`

takes as input an instance of the monad, `p`

, “containing” values of type `A`

. `map`

also receives as input a function which can transform a value of type `A`

into a new value of type `B`

. The job of `map`

is to find its way to each accessible element of type `A`

inside `p`

, apply `f`

to it, and encapsulate the result(s) in a new instance of `M`

. In the case of `Option`

, this would become:

let map = <A,B>(p:Option<A>, f:(_:A)=>B) : Option<B> =>

p.kind == "none" ? ({ kind:"none" })

: ({ kind:"some", v:f(p.v) })

The last point that distinguishes monads from other, simpler generic data types is that monads can be “joined” (also called “flattened” or “concatenated”). This means that an instance of a monad with another instance of the same monad inside itself can be converted to a single instance of the monad, thereby removing a containment level. This is a big deal, since it means that the monad is powerful enough to represent itself multiple times at once.

This leads us to the following signature:

let join = <A>(p:M<M<A>>) : M<A> => ...

In the case of `Option`

, this leads us to:

let join = <A>(p:Option<Option<A>>) : Option<A> =>

p.kind == "none" || p.v.kind == "none" ? ({ kind:"none" })

: ({ kind:"some", v:p.v.v })

It is also easy to see that, for lists, `join`

will concatenate all the elements of a `List<List<A>>`

into a single `List<A>`

.

A very common utility that is usually defined on monads is therefore the `bind`

operator that allows us to concatenate a monad, an operation that works on its content and produces new submonad(s) as result(s), and concatenates everything in a single resulting monad. Fortunately, such an operation is easily defined just in terms of `map`

and `join`

!

The definition of `bind`

is therefore (split on multiple lines for explanatory reasons, given that it could easily just be written as a one liner):

let bind = <A,B>(p:M<A>, k:(_:A) => M<B>) : M<B> => {

let pk:M<M<B> = map(p, k)

return join(pk)

}

The interesting aspect of bind is that it makes it possible to combine monadic operations together. For example, we could define safe division with `Option<number>`

in terms of:

let safe_div = (x:Option<number>, y:Option<number>) :

Option<number> =>

bind(x, v_x =>

bind(y, v_y =>

v_y == 0 ? fail<number>()

: unit(v_x / v_y)))

(where we assume we have already defined `let fail = <A>() => ({ kind:"none" })`

). Interestingly enough, since `safe_div`

also returns an `Option<number>`

, it can be used itself on the left-side of binding:

bind(safe_div(a, b), x =>

bind(safe_div(c,d), y =>

...))

### React monad

Monads are powerful, and indeed we see them explicitly and implicitly finding their way in many libraries, often in disguised form. Examples of monads are the `flatMap`

method of Immutablejs, the `then`

method of `Promise`

, and more. The flexibility of monads suggests (together with their host of widely used, existing implementations) that they can be used to simplify working in contexts ranging from graphics rendering, asynchronous computations, collection manipulation, IO, etc.

This led us to the question: “can React be encapsulated in a monadic interface” in order to remove some of its boilerplate and increase composability and safety?

The first step in order to answer such a question is the formulation of a generic data type encapsulating a monadic react component around an arbitrary type `A`

. In what sense is a React component parameterized by a type? Let us take a step back and consider what a React component does: it is instantiated with some properties, one or multiple of which will often be a callback. The component will then render its contents (represented as a `JSX.Element`

), perform its operations, and then eventually invoke its callback(s). The argument given to the callback is the only thing the rest of the application (the caller component) will ever see of the current component, meaning that the callback is invoked with a value of type `A`

which represents the *output* of a component. This leads us to the realization that a React component which yields outputs of type `A`

will take as input a property of type `callback:(res:A) => void`

, which is a callback to which we pass the results of the component. Since this callback will trigger the *rest* of the dataflow dependent on the current component, we call it `cont`

, short for *continuation.*

The signature of a monadic react component is therefore generalized to:

export type Cont<A> = (_:A) => void

export type C<A> = (cont:Cont<A>) => JSX.Element

`C`

will be the type of our monadic React components, which will invoke `cont`

whenever they have an output that they want to yield “to the rest of the program”.

Our `C`

datatype clearly shows in what sense monads are not mere containers of data: the values of type `A`

that will become the *output* produced by our component (for example, such a component might produce as outputs a string whenever the user types something) are passed to the continuation `cont`

. The values are neither *contained*, nor *saved* in `C`

, but rather dynamically computed and extracted on the fly. This makes `C`

a sort of (potentially infinite) *stream* of `A`

‘s.

The first step is to define a `unit`

function which instantiates a component “around” a result. This is easier done than said:

let unit = <A>(x:A) : C<A> =>

cont => cont(x) || null

This component does not really need to perform any actual rendering, therefore it simply returns `null`

right after passing the value `x`

along to the continuation.

We can then easily build a `map`

function for our component, which “simply” injects a fake continuation that will then translate the values with a transformation function:

let map = <A,B>(p:C<A>, f:(_:A) => B) : C<B> =>

(cont_b:Cont<B>) => p (x => cont_b(f(x)))

This implementation of `map`

is attractively simple: we create an adapter component `C<B>`

(a sort of placeholder) with its own callback, `cont_b`

. The placeholder `C<B>`

then just invokes `p`

with a custom-made continuation, `x => cont_b(f(x))`

, which is invoked by `p`

with values `x`

of type `A`

. These values are transformed via `f`

into values of type `B`

, which are then passed along as final output to the continuation `cont_b`

.

The final step is the `join`

function which flattens two components nested inside each other into a single final component. `join`

is slightly more difficult, as it requires caching the (renderable) result of the outer container in order to render it:

type JoinProps<A> = { p:C<C<A>>, cont:Cont<A> }

type JoinState<A> = { p_inner:"waiting"|JSX.Element, p_outer:JSX.Element }

class Join<A> extends React.Component<JoinProps<A>,JoinState<A>> {

constructor(props:JoinProps<A>,context:any) {

super()

this.state = { p_inner:"waiting", p_outer:props.p(p_inner =>

this.setState({...this.state,

p_inner:p_inner(x => props.cont(x))})) }

}

componentWillReceiveProps(new_props:JoinProps<A>) {

this.setState({ p_outer:new_props.p(p_inner =>

this.setState({...this.state,

p_inner:p_inner(x => new_props.cont((x))})) })

}

render() {

return <div>

{ this.state.p_outer }

{ this.state.p_inner == "waiting" ? null

: this.state.p_inner }

</div>

}

}

Unfortunately, `join`

must aggressively cache the previous results in order to “trick” React into not triggering too many spurious calls to `cont`

(we consider a call to `cont`

*spurious *when it is not performed as the result of an actual event, but rather because of the internal logic of React updates). This makes its implementation less pleasant to read.

The very last bit we need is a mechanism to instantiate a component inside a non-monadic React application. This is easier said than done: just invoke `C<A>`

with a suitable callback, inside the `render`

method of your component, and voilá! The library contains a component, called `simple_application : <A>(p:C<A>, cont:Cont<A>) : JSX.Element`

, which does exactly this.

#### Combinators

In addition to the fundamental interface of monads, it is usually convenient to implement some extra operators that make working with one’s library easier. In the case of monadic react, there are three very important operators that encode some fundamental concepts to compose and transform existing components. We will begin by describing the general shape of these combinators, and then we will show them in action with concrete examples.

The first such operator is `repeat`

. The signature of `repeat`

is

let repeat: <A>(key?: string, dbg?: () => string) => (p: (_: A) => C<A>) => (_: A) => C<A>

The (optional) `key`

and `dbg`

are parameters that respectively force a React key and print a debug message when the component is instantiated or updated. The real payload of `repeat`

though is the function, `p`

, which turns a value of type `A`

into a monadic component which will produce another `A`

as output (`C<A>`

). `repeat`

will keep invoking `p`

*with its last own output*, and `repeat`

will also yield the output of `p`

as if it were its own. `repeat`

therefore encapsulates the notion of *state* in React as the closure of an ever-looping component. The reason why `p`

has signature `A => C<A>`

is also significant: think of a component such as an `input`

box: it requires an initial value of type `string`

, and produces (via `onChange`

) outputs of type `string`

. `repeat`

expects such a component as `p`

, in this case with signature `string => C<string>`

.

Very often, multiple components are waiting for the user to interact with them, or for an api call to complete, but only the one that actually activates is of interest: the others can be ignored. In order to capture this pattern, we use the `any`

combinator, which signature reads:

let any: <A, B>(key?: string, className?: string, dbg?: () => string) => (ps: ((_: A) => C<B>)[]) => (_: A) => C<B>

`any`

takes as input an array of components `ps`

, each accepting an `A`

as input and potentially producing a `B`

as output. `any`

will pass its own input of type `A`

to each component in `ps`

, and the first one to yield an output will see its output yielded by `any`

as its own.

Sometimes, the various components we pass to `any`

are not intrinsically built to all process the same `A`

as input and the same `B`

as output. More often than not, `any`

works with a larger data structure than its elements. `retract`

offers a way to automatically map the input and output of these components with two appropriate functions, so that all of the `ps`

elements look like the same component. The signature of `retract`

is therefore:

let retract: <A, B>(key?: string, dbg?: () => string) => (inb: (_: A) => B, out: (_: A) => (_: B) => A, p: (_: B) => C<B>) => (_: A) => C<A>

`inb`

translates the input of the component to the desired type `B`

, and `out`

merges the output of the component with the previous input `A`

in order to determine the new value of `A`

.

#### Differences with actual implementation

It might be worth pointing out that the current implementation that you may download from npm differs in minor places from the one presented in the article: there are a few extra details such as additional callbacks, a global read-only context for shared utilities, etc. Moreover, the actual libraries contains tens of additional operators such as `filter`

, `button`

, `rich_text`

, and much more (even `routing`

).

Nevertheless, the core of the implementation and the associated concepts are exactly the same we just presented.

### A concrete example of practical usage

Let us now see a small concrete example of usage of monadic react. Our goal is to build a rich text editor which can be toggled from editable to view-only by pressing a button.

The state of our component will contain the text written so far with the editor, plus whether or not we are editing or viewing:

type Mode = "edit" | "view"

type EditToggleState = { mode:Mode, text:string }

The core of our component will be a `repeat`

encapsulating the idea that the `EditToggleState`

is indeed our state, and as such is continuously fed back into the component itself:

repeat<EditToggleState>("edit toggle sample")(

...

)({ mode:"edit", text:"" })

The first argument to `repeat`

is the React key we want to set. It is always good practice to help React identify components quickly with a key, and our example makes no exception to this good practice.

The second argument is the core of our form, which we will specify in a moment. It will need to have signature `EditToggleState => C<EditToggleState>`

.

The third argument is the initial state.

The core of our form will be made out of two separate sub-components: a button and a text editor. Since only one of them will be active at any given time, we will group them with `any`

:

repeat<EditToggleState>("edit toggle sample")(

any<EditToggleState, EditToggleState>()([

...,

...

]))({ mode:"edit", text:"" })

The two arguments to `any`

will be the button and the rich text editor. Unfortunately, but not unsurprisingly, these components do not manipulate the same types, and obviously neither of them is capable of manipulating `EditToggleState`

directly. For this reason, they will both be encapsulated in a `retract`

that converts `EditToggleState`

back and forth from, respectively, the edit mode and the text:

repeat<EditToggleState>("edit toggle sample")(

any<EditToggleState, EditToggleState>()([

retract<EditToggleState, Mode>()(s => s.mode, s => m => ({...s, mode:m}),

mode => button<Mode>("Toggle editing")(mode == "view" ? "edit" : "view")

),

state =>

retract<EditToggleState, string>()(s => s.text, s => t => ({...s, text:t}),

rich_text(state.mode)

)(state)

])

)({ mode:"edit", text:"" })

The result is exactly as expected:

In about a dozen lines of code we have assembled a React form, with the added bonuses of enforced referential transparency and type safety at a higher level than when using React on its own.

### See monadic react in action

If you are curious to see monadic react in action and play with it, you can head to the GitHub repository, the npm package, or the samples repository.

If you are wondering whether or not monadic react is ready for production, we believe the answer to be yes. The first website fully powered by monadic react is live and in use: GrandeOmega, featuring a full-blown editable CMS completely made in monadic react. The site is still in “startup mode”, meaning we are still working on plenty of things, but it clearly shows the promise and maturity of the framework. We believe we could not have set the site up so quickly and with so few bugs without the library.