# Functors, Applicatives, and Monads in Elixir

Big ol' note:By no means am I an expert on any of the below content. I'm currently learning this to the best of my ability and thought to write down my experiences and thoughts with implementing these in Elixir.

We're going to be comparing Elixir protocols with Haskell's type classes using a go-to type for the subject at hand: `Maybe`

. The `Maybe`

type encapsulates an optional value. A value of type `Maybe a`

either contains a value of type `a`

(represented as `Just a`

), or it is empty (represented as `Nothing`

). Here's how Haskell defines the type:

```
data Maybe a = Just a
| Nothing
```

Because of Elixir's lack of strong typing and type constructors, we define the Elixir version of `Maybe`

slightly different:

```
defmodule Maybe do
@type t :: %__MODULE__{
just: term,
nothing: boolean
}
defstruct just: nil,
nothing: false
def just(v), do: __MODULE__ |> struct(just: v)
def nothing, do: __MODULE__ |> struct(nothing: true)
end
```

The struct is acting as a wrapper for the values and the module contains some helper functions to act as a pseudo-replacement for Haskell's type constructors. In Elixir, the type `Maybe a`

now either contains a value of type `term`

(represented as `Maybe.just(term)`

) or is empty (represented as `Maybe.nothing`

).

## Functor

Using functors, we can generalize how `Enum.map`

works for `Enumerable`

s on any data type, including `Maybe`

. We can accomplish this by generalizing the action and implementing that action for the desired data types. This generalized action for Functors is known as `fmap`

. Take a look at the definition for the `Functor`

protocol:

```
defprotocol Functor do
@spec fmap(t, (term -> term)) :: t
def fmap(functor, fun)
end
```

and compare it to Haskell's `Functor`

type class:

```
class Functor f where
fmap :: (a -> b) -> f a -> f b
```

We can start to see similarities between the two purely by looking at the types. Both require a functor and function as arguments. Haskell's `f a`

represents a functor with a type constructor of `a`

, similar to `[a]`

being a list of `a`

s. You may notice that the order of the arguments in both differ. This mostly has to do with how Elixir's Protocol dispatch process works as it looks at the first argument's type in order to dispatch the call to the correct implementation.

Now, any type that wishes to be a functor only needs to implement the `fmap`

function, using Elixir's `defimpl`

macro or Haskell's `instance`

keyword:

```
defimpl Functor, for: Maybe do
def fmap(%{nothing: true} = f, _), do: f
def fmap(%{just: a}, fun) do
fun
|> apply([a])
|> Maybe.just
end
end
```

```
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
```

While the Haskell version is more concise, they both define the same core functionality. Calling `fmap`

on a "nothing" will always return a "nothing", ignoring the function that is passed as well. Calling `fmap`

on a value will unwrap the value by pattern matching the `Maybe`

functor and applying the passed function on the value.

### Defining and Using Functors

Let's take a look at what this looks like in use:

```
f0 = fn x -> x + 2 end
Maybe.just(5) # Define
|> Functor.fmap(f0) # Use
# %Maybe{just: 7, nothing: false}
```

Since our functors in Elixir are just simple structs, our "Just 5" value can be defined in the same variety of ways: `Maybe.just(5)`

, `%Maybe{just: 5}`

, `struct(Maybe, just: 5)`

, etc. The power of the functor comes from the `Functor`

protocol. When we want to work with the functor, we pass it to `fmap/2`

along with a function, in this case a small anonymous function that adds `2`

. From here, Elixir's protocol dispatch takes over, inspecting the functor's type to direct the call to the functor's implementation of `fmap/2`

.

The result of `fmap/2`

is another functor, so if necessary, we can continue to pipe additional calls to `fmap/2`

. At any time during this pipeline, any one of the included functions could potentially return a "nothing" value (`Maybe.nothing`

) without throwing an error.

```
f1 = fn x-> x + 2 end
f2 = fn _ -> Maybe.nothing end
f3 = fn x -> x * 3 end
Maybe.just(5)
|> Functor.fmap(f1)
|> Functor.fmap(f2)
|> Functor.fmap(f3)
# %Maybe{just: nil, nothing: true}
```

In a real world situation, this allows us to worry less about catching and accounting for possible points of failure since our implementation of `Functor`

for `Maybe`

already accounts for this case (remember, calling `fmap`

on a "nothing" will always return a "nothing").

## Applicative (Functor)

I'm going to leave out the Haskell from here until I can figure how to handle a few things better in Elixir.

Applicatives (or more specifically applicative functors) are a special form of `Functor`

where the value within the functor is a function.

```
defprotocol Applicative do
@spec apply(t, Functor.t) :: t
def apply(fun, f)
end
defimpl Applicative, for: Maybe do
def apply(%{nothing: true} = f, _), do: f
def apply(%{just: fun}, f) do
f |> Control.Functor.fmap(fun)
end
end
```

`Maybe`

is now a `Functor`

as well as an `Applicative`

. Again, our `Maybe`

implementation of `Applicative`

destructures the first argument, returning a "nothing" value if one is present. However, now it is expected that the value in our functor is a function of type `(term -> term)`

. Here's an example where this would be useful:

```
f4 = fn file ->
case File.stat(file) do
{:ok, s} ->
Maybe.just(&(&1 |> magic_function(s))
{:error, _} ->
Maybe.nothing
end
end
```

I know this is a convoluted example with simpler alternatives. Let me know if you have a better example for this.

In this specific case, we've created a closure over the `File.Stat`

variable (`s`

) using it in an eventual call to our `magic_function/2`

function. We only want the call to `magic_function/2`

to occur when the file actually exists, so `Maybe`

comes in to save the day.

Because our anonymous function is wrapped in a `Maybe`

, it might be tricky call this function with another `Maybe`

. We could pull out the function manually:

```
# "something.txt" exists
%Maybe{just: f5} = f4.("something.txt")
```

But this would need to be duplicated everywhere it was necessary. There also may be cases where this process would be too cumbersome to carry out manually. Lucky for us, the implementations of `Applicative.apply/2`

will handle this for all functors that have it available.

```
f4.("something.txt")
|> Applicative.apply(Maybe.just(5))
```

## Monad

While I definitely don't want to go down the "let's describe what a monad is" road, I will say I've read that it is best to think of a monad as an abstract data type of actions. A list monad represents actions on a list. An IO monad represents actions on IO.

```
defprotocol Monad do
@spec bind(t, (term -> t)) :: t
def bind(m, fun)
end
```

Without going into detail just yet on `Monad`

, did you notice any similarities to `Functor`

and `Applicative`

? Here are their typespecs right next to each other (expanding `Applicative`

's to clear it up):

```
@spec fmap( t, (term -> term)) :: t # Functor
@spec apply(t [(term -> term)], Functor.t) :: t # Applicative
@spec bind( t, (term -> t)) :: t # Monad
```

They all accept a value and a function to modify that value, returning the type again.

In `Functor.fmap/2`

, we take an unwrapped value, apply the function, and return a wrapped result. In `Applicative.apply/2`

, we do the same as `Functor.fmap/2`

, but the function is wrapped as well as the value. In `Monad.bind/2`

, we do the same as `Functor.fmap/2`

as well, but the function argument returns the wrapped value opposed to it being wrapped after the fact.

```
defimpl Monad, for: Maybe do
def bind(%{nothing: true} = f, _), do: f
def bind(%{just: v}, fun) do
fun |> apply([v])
end
end
```

Following the types, the implementation for `bind/2`

looks very similar to that of `fmap/2`

and `apply/2`

because they are all similar. The difference come down to how the functions receive the data and how it expects the function to transform that data.

## Wrapping Up

In my eyes, it's yet to be determined whether or not Elixir and Erlang really need functors, applicatives, and monads. The data types that follow these protocols can structure things in a way so that they can hide state, side-effects, etc. away from the pure side of the code, and Haskell uses them to it's advantage to become more than just an academic language and to be able to solve real world problems.

But since Elixir is a dynamic language, we don't always have the compiler to tell us what to do. We can add side-effecting code in our pure functions and others would be none the wiser, but typically, Elixir and Erlang developers will hide the same state, side-effects, etc. away into designated actors. There's no need for a `State`

monad to maintain state between function calls because we have abstractions around actors like `GenServer`

and `Agent`

to do this for us, interfacing with those actors by message passing.

I'm going to keep going down this adventurous path for a little while longer, but I don't quite yet see how many cases that I'd use these in lieu of actors.

If you're interested in seeing the code behind this post, take a look at

`Control`

, an exploratory look into functors, applicatives, and monads for Elixir.