Functors and Monads in plain TypeScript
Tags: monad, promise, array, functor
Published: 2019-12-13 18:12:59

Many words are already said about `Monads`. I didn't really want to write yet another article explaining them. However, while I was working on documentation for my [amonad](https://www.npmjs.com/package/amonad) library, I realized that I could not find any place in which I can refer for a quick introduction to the concept. Although, it appears to be too big to make it part of the documentation itself. So, here you are.

>The monadic curse is that once someone learns what monads are and how to use them, they lose the ability to explain them to other people. 
>
> Douglas Crockford

I think it might be caused by a too high amount of mathematical details in full explanation. I will try my best to make this basic introduction more practical. Since I believe that I am still capable of explaining them to others, you might consider that I didn't completely get them.

So, I am sorry if there are some imprecisions in my reasoning, and I will be grateful to see any feedback or correction in the comments below.

# Execution Order

The concepts we are going to discuss today initially came from *purely functional programming languages*. Naturally, they are not capable of expressing an *execution order* of computations. Hence, there is a formal way to achieve it.

## Pure functions

Before jumping to the explanation of different possibilities to model execution order, let us take a glance at the feature which gave the name of the language family since it is going to be a great help further.

There are three criteria which have to be satisfied with the function to be *pure*:

 - It should not be capable of doing any *side effects*, or in other words, the *external mutable state* can not be modified.
 - The result of its work has to be represented by the return value.
 - The same combination of input arguments should always produce the same result.

*Pure functions* are highly deterministic. It is easy to reason about them since their application can be easily replaced with their bodies. This property is called *referential transparency*. It should be even possible to cache its computation's result and use a lookup table for the optimization of calls with the same input value. In some sense, such functions are similar to mathematical ones, like `sin`, `cosine`, `sqrt`, and so on. Does anybody remember how to use a logarithmic table?

## Function composition

Due to outlined qualities, *pure functions* can be combined via a *composition*, like `cos( sqrt(x) )`. So, that `sqrt` is applied to `x`, and the result is passed to `cos`. It is actually possible to use any of them in such a way: `foo2( foo1(arg) )`.

If we take a closer look at the previously mentioned example, we will, eventually, find that an *execution order* can be preserved by *function composition*. The implication of the fact allows us to conclude that the code presented in two following listing is equivalent.

```typescript
const result1 = foo1(arg1);
const result2 = foo2(result1);
```

```typescript
const result2 = foo2(
 foo1(arg1)
);
```

It is also possible to extract *function composition* in a separate stage by defining a function which will compose two functions in a following way: 

```typescript 
function compose <A, B, C>( f1: (value: A) => B, f2: (value: B) => C ): (value: A) => C {
    return value => f2( f1( value ) )
}
```

It will give us a bit more coherent approach to rewriting the presented snippets.

```typescript
const foo12 = compose(
 foo1,
 foo2
);
const result2 = foo12(arg1);
```

```typescript
const result2 = compose(
 foo1,
 foo2
)(arg1);
```

# Into functor

There is a drawback to such an implementation. It is hardly possible to define a function which is capable of combining an arbitrary number of functions in a type-safe manner. Indeed, it is possible to resolve the problem via a container encloses the value inside. It has to be able to manage a *function application* to its content. 

There are only two things that are required in that case: container constructor and function, which can apply a transformation to the content. There is a common name for such an abstraction. It is called `Functor`.

```typescript
interface Functor<A> {
    map<B>( transform: (value: A) => B ): Functor<B>;
}
```

It allows as to express the piece of code following way:

```typescript
const result2 = new Functor<Arg1>(arg1)
 .map(foo1)
 .map(foo2);
```

The function responsible for application is traditionally called `map` or somehow similarly. In our case, for convenience reason, it was defined as a method. It takes a function that is intended for an application to the content of the `Functor` and applies it. The action produces a new value, which is again wrapped in a `Functor` of the same type, which provides us with a possibility to chain `map` calls.

It is also possible to define `map` as an external *pure function*. 

```typescript 
function map<A, B>( functor: Functor<A>, transform: (value: A) => B ): Functor<B>
```

In that case, it is a bit more clear why the preservation of order is concluded from a *function composition*.

```typescript
const result2 = map(
    map(
        new Functor(arg1),
        foo1
    ),
    foo2
)
```

# Functor's anatomy

For a long time, I had the idea that limitations force creativity. So, a loss of ability to define an execution order brought people to `Functor`, which helps to preserve it via *function composition*. Besides that, it abstracts an actual application of a function to the data. That opens a possibility to internally adjust applied function in a wide range of ways.

Initially, we defined `Functor` as a simple container. However, it also can be considered as some new type, derived as a transformation of inclosed value, like Mapped types in TypeScript. Although, the container is just a a particular type of such a mapping. That's why the `map` method gets an additional responsibility of turning provided functions from a function capable of handling base type into a function able to work with value transformed by a `Functor` constructor. This way of thinking expands the range of abstractions that can be formalized by `Functors`.

The previously discussed example of `Functor` is, actually, the most basic one, and it is called `Identity Functor`. As you might already notice, the pattern is very similar to JavaScript's `Array`, since `Array` is one of the most common instances of `Functor`. Its `map` takes a function applicable to a type of single element of the `Array` and applies it to each value individually. In this way, it applies it to the entire `Functor`. Nowadays it is a well-known pattern for collections. 

Another wide-spread example of such an approach is JavaScript `Promise`. It has a `then` method, which satisfies the signature of the `map` function and abstracts the fact that the data might be absent or only available later. It worth to mention that `then`'s signature is a bit more sophisticated. Therefore `Promise` is a bit more than just another `Functor`.

# Monad

`Promise` is utilized for modeling of asynchronous operations, which are mostly related to IO. Due to a particular case of its utilization, it frequently has to rely on previously retreated information. For example, there is an asynchronous call to a remote API, which gets information and utilizes it to subsequent requests, which is based on the prior result.

```typescript
const result2 = getAsyncData1(arg1)
    .then( value => {
        const result1 = processValue(value);
        return getAsyncData2(result1);
    })
```

The function passed to `then()` has a signature `<A, B>(value: A) => Promise<B>`. According to a signature defined for `Functor`, the type of `result1` has to be `Promise<Promise<Result1>>`. It would be totally unbearable to write any relatively complex code which requires a lot of subsequent asynchronous operations. Moreover, it would not make any sense to have several nested `Promises` since all of them essentially represent the same. If any of the operations in the sequence are failed or delayed, a whole chain is going to be affected. Therefore it should be possible to flatten them in a single one. 

The described situation is so wide-spread that `then()` was implemented in a special way to be capable of composing such embellished functions. It appears to be handy, that's why it was formalized under the name of `Monad`. Similarly to `Functor`, it has a constructor and a special function capable of applying value to the data hidden inside. Mathematically speaking, the function managing the application process is traditionally called `bind`. Nonetheless, in many programming languages, it is called simply `flatMap`. After all, the same can basically be achieved by a combination of `map` and `flatten` functions. I think the naming is quite apparent in that case.

```typescript
interface Monad<A> {
    bind<B>( transform: (value: A) => Monad<B> ): Monad<B>;
}
```

Due to the dynamic nature of JavaScript's type system, `Promise.prototype.then()` was implemented in a way that is capable of handling `<A, B>(value: A) => B` as well as `<A, B>(value: A) => Promise<B>` functions — thus satisfying requirements for `Monad` as well as for `Functor`.


# Conclusion

In the article, we discussed the possibility of expressing an execution order via *function compositions* and how it naturally leads us to the concept of `Functors` and later `Monads`. `Monads` are superior to `Functors`, because they are capable of modelling `Functor` by raising the output type of `A -> B` function to `Monad<B>` type with a `Monad` constructor if needed. 

`Array` and `Promise` were described as the most well-known examples of their kinds, while there are a lot of other useful `Monads` and ways to apply them in real-life applications. `Monad` is a very powerful abstraction that opens a lot more exotic possibilities that lie beyond the scope of the introduction article.


There is a TypeScript implementation of  `Result` and `Maybe` `Monads` in [amonad](https://www.npmjs.com/package/amonad) library. The documentation has a pretty good introduction to them and their usage. It will help you to expand your knowledge of the topic and learn more about monadic error handling, particularly.