## DEV Community

Alexey Tukalo

Posted on • Updated on

# Functors and Monads in plain TypeScript

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 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.

``````const result1 = foo1(arg1);
const result2 = foo2(result1);
``````
``````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:

``````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.

``````const foo12 = compose(
foo1,
foo2
);
const result2 = foo12(arg1);
``````
``````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`.

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

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

``````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.

``````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.

``````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.

``````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.

``````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 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.