Functors, Applicatives, And Monads In Pictures (In ReasonML)
Tags: reason, haskell, functional
Published: 2020-01-12 02:46:24

This is a translation of [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) 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](http://adit.io/index.html) ([@_egonschiele](https://twitter.com/_egonschiele)) the author of the original version.

---

Here's a simple value:

![](http://adit.io/imgs/functors/value.png)

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

![](http://adit.io/imgs/functors/value_apply.png)

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:

![](http://adit.io/imgs/functors/value_and_context.png)

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:

![](http://adit.io/imgs/functors/context.png)

```reasonml
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:

![](http://adit.io/imgs/functors/no_fmap_ouch.png)

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

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

![](http://adit.io/imgs/functors/fmap_apply.png)

**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](http://learnyouahaskell.com/types-and-typeclasses#typeclasses-101).

In ReasonML we don't have type classes yet, but [they are being worked on in OCaml](http://ocamllabs.io/doc/implicits.html), and therefore ReasonML.

Here's the definition:

![](http://adit.io/imgs/functors/functor_def.png)

A `Functor` is any data type that defines how `fmap` applies to it. Here's how `fmap` works:

![](http://adit.io/imgs/functors/fmap_def.png)

So we can do this:

```reasonml
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:

```reasonml
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));`:

![](http://adit.io/imgs/functors/fmap_just.png)

So then you're like, alright `fmap`, please apply `(+3)` to a `Nothing`?

![](http://adit.io/imgs/functors/fmap_nothing.png)

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

```reasonml
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:

```reasonml
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:

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

So we can now write:

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

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

![](http://adit.io/imgs/functors/fmap_list.png)

Lists can operate as functors too!

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

```reasonml
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`:

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

So we can now write:

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

Here's a function:

![](http://adit.io/imgs/functors/function_with_value.png)

Here's a function applied to another function:

![](http://adit.io/imgs/functors/fmap_function.png)

The result is just another function!

```reasonml
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:

![](http://adit.io/imgs/functors/value_and_context.png)

But our functions are wrapped in a context too!

![](http://adit.io/imgs/functors/function_and_context.png)

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.

![](http://adit.io/imgs/functors/applicative_just.png)

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

```reasonml
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:


```reasonml
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:

```reasonml
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:

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

![](http://adit.io/imgs/functors/applicative_list.png)

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?

```reasonml
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:

```reasonml
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!"

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

## Monads

How to learn about Monads:

1. Get a PhD in computer science.
2. 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:

![](http://adit.io/imgs/functors/fmap.png)

Applicatives apply a wrapped function to a wrapped value:

![](http://adit.io/imgs/functors/applicative.png)

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:

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

let (>>=) = bind;
```

![](http://adit.io/imgs/functors/context.png)

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):

```reasonml
/*
 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;
  };
```

![](http://adit.io/imgs/functors/half.png)

What if we feed it a wrapped value?

![](http://adit.io/imgs/functors/half_ouch.png)

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

![](http://adit.io/imgs/functors/plunger.jpg)

Here's how it works:

```reasonml
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:

![](http://adit.io/imgs/functors/bind_def.png)

Let's make our `Maybe` into a monad by adding the `bind` functions.

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

let (>>=) = bind;
```

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

![](http://adit.io/imgs/functors/monad_just.png)

And if you pass in a `Nothing` it's even simpler:

![](http://adit.io/imgs/functors/monad_nothing.png)

You can also chain these calls:

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

![](http://adit.io/imgs/functors/monad_chain.png)

![](http://adit.io/imgs/functors/whoa.png)

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:

![](http://adit.io/imgs/functors/io.png)

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:

![](http://adit.io/imgs/functors/getLine.png)

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

![](http://adit.io/imgs/functors/readFile.png)

`putStrLn` takes a string and prints it:

![](http://adit.io/imgs/functors/putStrLn.png)

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

```reasonml
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](https://github.com/kevanstannard/reasonml-in-pictures/blob/master/src/Index.re).

All three functions take a regular value (or no value) and return a wrapped `Promise` value. We can chain all of these using `>>=`!

![](http://adit.io/imgs/functors/monad_io.png)

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

Aw yeah! Front row seats to the monad show!

## Conclusion

1. A functor is a data type that implements the `fmap` function.
2. An applicative is a data type that implements the `apply` function.
3. 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?

![](http://adit.io/imgs/functors/recap.png)

**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](http://learnyouahaskell.com/a-fistful-of-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](http://adit.io/index.html) for writing the [original version of this post](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) :heart: