This is a translation of Functors, Applicatives, And Monads In Pictures from Haskell into ReasonML.

I take no credit for this work, and if you enjoy this post be sure to say thanks to Aditya Bhargava (@_egonschiele) the author of the original version.

Here's a simple value:

And we know how to apply a function to this value:

Simple enough. Let's extend this by saying that any value can be in a context. For now you can think of a context as a box that you can put a value in:

Now when you apply a function to this value, you'll get different results **depending on the context**. This is the idea that Functors, Applicatives, Monads, Arrows etc are all based on.

Let's create a `Maybe`

data type that defines two related contexts:

```
module Maybe = {
type t('a) =
| Nothing
| Just('a);
}
```

In a second we'll see how function application is different when something is a `Just(a)`

versus a `Nothing`

. First let's talk about Functors!

## Functors

When a value is wrapped in a context, you can't apply a normal function to it:

This is where `fmap`

comes in. `fmap`

is from the street, `fmap`

is hip to contexts. `fmap`

knows how to apply functions to values that are wrapped in a context.

Suppose you want to apply `(+3)`

to `Just(2)`

. We can implement `fmap`

:

```
Maybe.fmap((+)(3), Just(2));
// Just(5)
```

**Bam!** `fmap`

shows us how it's done!

## Just what is a Functor, really?

`Functor`

is a class of functions that define an `fmap`

function.

In Haskell they are defined as a type class.

In ReasonML we don't have type classes yet, but they are being worked on in OCaml, and therefore ReasonML.

Here's the definition:

A `Functor`

is any data type that defines how `fmap`

applies to it. Here's how `fmap`

works:

So we can do this:

```
Maybe.fmap((+)(3), Just(2));
// Just(5)
```

This specifies how `fmap`

applies to `Just`

s and `Nothing`

s:

Let's add `fmap`

to our `Maybe`

module:

```
let fmap = (f, m) => {
switch (m) {
| Nothing => Nothing
| Just(a) => Just(f(a))
};
};
```

Here's what is happening behind the scenes when we write `Maybe.fmap((+)(3), Just(2));`

:

So then you're like, alright `fmap`

, please apply `(+3)`

to a `Nothing`

?

```
Maybe.fmap((+)(3), Nothing)
// Nothing
```

Like Morpheus in the Matrix, `fmap`

knows just what to do; you start with `Nothing`

, and you end up with `Nothing`

! `fmap`

is zen. Now it makes sense why the `Maybe`

data type exists. For example, here's how you work with a database record in a language without `Maybe`

:

```
post = Post.find_by_id(1)
if post
return post.title
else
return nil
end
```

Let's create a simple `Post`

module in ReasonML with these functions.

```
module Post = {
type t = {
id: int,
title: "string,"
};
let make = (id, title) => {id, title};
let fmap = (f, post) => f(post);
let getPostTitle = post => post.title;
let findPost = id => make(id, "Post #" ++ string_of_int(id));
};
```

Now we can write:

```
Post.(fmap(getPostTitle, findPost(1)));
```

If `findPost`

returns a post, we will get the title with `getPostTitle`

. If it returns `Nothing`

, we will return `Nothing`

! Pretty neat, huh?

In Haskell, `<$>`

is the common infix version of `fmap`

.

In ReasonML we can create an equivalent alias. Adding to our `Post`

module:

```
let (<$>) = fmap;
```

So we can now write:

```
Post.(getPostTitle <$> findPost(1));
```

Here's another example: what happens when you apply a function to a list?

Lists can operate as functors too!

In ReasonML we can make use of the list map function:

```
List.map
```

Okay, okay, one last example: what happens when you apply a function to another function?

For this case we can define a `Function`

module that has `fmap`

:

```
module Function = {
let fmap = (f, g, x) => f(g(x));
};
```

So we can now write:

```
Function.fmap((+)(3), (+)(1));
```

Here's a function:

Here's a function applied to another function:

The result is just another function!

```
let foo = Function.fmap((+)(3), (+)(2));
foo(10);
// 15
```

So functions can be Functors too!

When you use `fmap`

on a function, you're just doing function composition!

## Applicatives

Applicatives take it to the next level. With an applicative, our values are wrapped in a context, just like Functors:

But our functions are wrapped in a context too!

Yeah. Let that sink in. Applicatives don't kid around. They know how to apply a function *wrapped in a context* to a value *wrapped in a context*:

Applicatives define an `apply`

function, also written as `<*>`

in Haskell, which we can create an alias for in ReasonML.

Let's add the applicative functions to our `Maybe`

module:

```
let apply = (mf, mv) => {
switch (mv) {
| Nothing => Nothing
| Just(v) =>
switch (mf) {
| Nothing => Nothing
| Just(f) => Just(f(v))
}
};
};
let (<*>) = apply;
```

Here's an example using them:

```
Maybe.(Just((+)(3)) <*> Just(2));
// Just(5)
```

Let's also define applicative functions for a list. We'll create a `MyList`

module to avoid name clashes with the built in `List`

module:

```
module MyList = {
type apply('a, 'b) = (list('a => 'b), list('a)) => list('b);
let apply: apply('a, 'b) =
(fs, xs) => List.flatten(List.map(f => List.map(f, xs), fs));
let (<*>) = apply;
};
```

Using `<*>`

can lead to some interesting situations. For example:

```
let funList = [(*)(2), (+)(3)];
let valList = [1, 2, 3];
MyList.(funList <*> valList);
// [2, 4, 6, 4, 5, 6]
```

Here's something you can do with Applicatives that you can't do with Functors. How do you apply a function that takes two arguments to two wrapped values?

```
Maybe.((+) <$> Just(5));
// Just((+)(5))
Maybe.(Just((+)(5)) <$> Just(4));
// ERROR ??? WHAT DOES THIS EVEN MEAN WHY IS THE FUNCTION WRAPPED IN A JUST
```

Applicatives:

```
Maybe.((+) <$> Just(5));
// Just((+)(5))
Maybe.(Just((+)(5)) <*> Just(3));
// Just(8)
```

`Applicative`

pushes `Functor`

aside. "Big boys can use functions with any number of arguments," it says. "Armed with `<$>`

and `<*>`

, I can take any function that expects any number of unwrapped values. Then I pass it all wrapped values, and I get a wrapped value out! AHAHAHAHAH!"

```
Maybe.((*) <$> Just(5) <*> Just(3));
```

## Monads

How to learn about Monads:

- Get a PhD in computer science.
- Throw it away because you don't need it for this section!

Monads add a new twist.

Functors apply a function to a wrapped value:

Applicatives apply a wrapped function to a wrapped value:

Monads apply a function that **returns a wrapped value** to a wrapped value.

Monads have a function `bind`

, or the operator alias `>>=`

to do this.

Let's see an example.

First, we'll need to add bind to our good ol' `Maybe`

module:

```
let bind = (mv, f) => {
switch (mv) {
| Nothing => Nothing
| Just(v) => f(v)
};
};
let (>>=) = bind;
```

Suppose `half`

is a function that only works on even numbers:

Let's write `half`

in ReasonML (we'll also need to define `even`

and `odd`

functions):

```
/*
Mutually recursive function
https://ocaml.org/learn/tutorials/labels.html
*/
let rec even = x =>
if (x <= 0) {
true;
} else {
odd(x - 1);
}
and odd = x =>
if (x <= 0) {
false;
} else {
even(x - 1);
};
let half = x =>
if (even(x)) {
Maybe.Just(x / 2);
} else {
Nothing;
};
```

What if we feed it a wrapped value?

We need to use `>>=`

to shove our wrapped value into the function. Here's a photo of `>>=`

:

Here's how it works:

```
Maybe.(Just(3) >>= half);
// Nothing
Maybe.(Just(4) >>= half);
// Just(2)
Maybe.(Nothing >>= half);
// Nothing
```

What's happening inside? `Monad`

defines a `bind`

(or `>>=`

) function:

Let's make our `Maybe`

into a monad by adding the `bind`

functions.

```
let bind = (mv, f) => {
switch (mv) {
| Nothing => Nothing
| Just(v) => f(v)
};
};
let (>>=) = bind;
```

Here it is in action with a `Just(3)`

!

And if you pass in a `Nothing`

it's even simpler:

You can also chain these calls:

```
Maybe.(Just(20) >>= half >>= half >>= half);
```

Cool stuff! So now we have implemented `Maybe`

to be a `Functor`

, an `Applicative`

, and a `Monad`

.

Now let's mosey on over to another example and create an `IO`

monad:

The `IO`

monad exists in Haskell, but we will declare our own in ReasonML.

Specifically three functions. `getLine`

takes no arguments and gets user input:

`readFile`

takes a string (a filename) and returns that file's contents:

`putStrLn`

takes a string and prints it:

Our `IO`

module might look something like this (leaving out implementation details of the helper functions):

```
module IO = {
type t = Js.Promise.t(string);
type bind('a, 'b) = (t, string => t) => t;
let bind: bind('a, 'b) = (pa, f) => pa |> Js.Promise.then_(a => f(a));
let (>>=) = bind;
type getLine = unit => t;
let getLine = ...
type readFile = string => t;
let readFile = ...
type putStrLn = string => t;
let putStrLn = ...
};
```

If you're interested, the full source code is available.

All three functions take a regular value (or no value) and return a wrapped `Promise`

value. We can chain all of these using `>>=`

!

```
IO.(getLine() >>= readFile >>= putStrLn);
```

Aw yeah! Front row seats to the monad show!

## Conclusion

- A functor is a data type that implements the
`fmap`

function. - An applicative is a data type that implements the
`apply`

function. - A monad is a data type that implements the
`bind`

function.

The `Maybe`

module in our examples implements all three, so it is a functor, an applicative, and a monad.

What is the difference between the three?

**Functors**: you apply a function to a wrapped value using `fmap`

or `<$>`

.

**Applicatives**: you apply a wrapped function to a wrapped value using `apply`

or `<*>`

.

**Monads**: you apply a function that returns a wrapped value, to a wrapped value using `bind`

or `>>=`

.

So, dear friend (I think we are friends by this point), I think we both agree that monads are easy and a SMART IDEA(tm). Now that you've wet your whistle on this guide, why not pull a Mel Gibson and grab the whole bottle. Check out LYAH's section on Monads. There's a lot of things I've glossed over because Miran does a great job going in-depth with this stuff.

If you feel there is something I could change to improve this translation to ReasonML please let me know.

Thanks again to Aditya Bhargava for writing the original version of this post ❤️

## Top comments (3)

Thank you for such a fun and understandable explanation!

Thank you for this.

One remark: I would add a note that the Maybe type is called Option in ReasonML, Just is equivalent to Some and Nothing to None.

Edit: And bind is (sometimes) called flatMap.

nice