Every time I read Learn You a Haskell, I get something new out of it.
This most recent time through, I think I’ve finally gained some insight into the
`Applicative`

type class.

I’ve been writing Haskell for some time and have developed an intuition and
explanation for `Monad`

. This is probably because monads are so prevalent in
Haskell code that you can’t help but get used to them. I knew that `Applicative`

was similar but weaker, and that it should be a super class of `Monad`

but since
it arrived later it is not. I now think I have a general understanding of how
`Applicative`

is different, why it’s useful, and I would like to bring anyone
else who glossed over `Applicative`

on the way to `Monad`

up to speed.

The `Applicative`

type class represents applicative functors, so it makes sense
to start with a brief description of functors that are *not* applicative.

## Values in a Box ๐

A functor is any container-like type which offers a way to transform a normal function into one that operates on contained values.

Formally:

```
fmap :: Functor f -- for any functor,
=> ( a -> b) -- take a normal function,
-> (f a -> f b) -- and make one that works on contained values
```

Some prefer to think of it like this:

```
fmap :: Functor f -- for any functor,
=> (a -> b) -- take a normal function,
-> f a -- and a contained value,
-> f b -- and return the contained result of applying that
-- function to that value
```

Because `(->)`

is right-associative, we can reason about and use this function
either way – with the former being more useful to the current discussion.

This is the first small step in the ultimate goal between all three of these
type classes: allow us to work with values with context (in this case, a
container of some sort) as if that context weren’t present at all. We give a
normal function to `fmap`

and it sorts out how to deal with the container,
whatever it may be.

## Functions in a Box ๐

To say that a functor is “applicative”, we mean that the contained value *can be
applied*. In other words, it’s a function.

An applicative functor is any container-like type which offers a way to
transform a *contained* function into one that can operate on contained values.

```
(<*>) :: Applicative f -- for any applicative functor,
=> f (a -> b) -- take a contained function,
-> (f a -> f b) -- and make one that works on contained values
```

Again, we could also think of it like this:

```
(<*>) :: Applicative f -- for any applicative functor,
=> f (a -> b) -- take a contained function,
-> f a -- and a contained value,
-> f b -- and return a contained result
```

Applicative functors also have a way to take an un-contained function and put it into a container:

```
pure :: Applicative f -- for any applicative functor,
=> (a -> b) -- take a normal function,
-> f (a -> b) -- and put it in a container
```

In actuality, the type signature is simpler: `a -> f a`

. Since `a`

literally
means “any type”, it can certainly represent the type `(a -> b)`

too.

```
pure :: Applicative f => a -> f a
```

Understanding this is very important for understanding the usefulness of
`Applicative`

. Even though the type signature for `(<*>)`

starts with `f (a -> b)`

, it can also be used with functions taking any number of arguments.

Consider the following:

```
:: f (a -> b -> c) -> f a -> f (b -> c)
```

Is this `(<*>)`

or not?

Instead of writing its signature with `b`

, lets use a question mark:

```
(<*>) :: f (a -> ?) -> f a -> f ?
```

Indeed it is: substitute the type `(b -> c)`

for every `?`

, rather than the
simple `b`

in the actual class definition.

## One In, One Out ๐

What you just saw was a very concrete example of the benefits of how `(->)`

works. When we say “a function of *n* arguments”, we’re actually lying. All
functions in Haskell take exactly one argument. Multi-argument functions are
really single-argument functions that return other single-argument functions
that accept the remaining arguments via the same process.

Using the question mark approach, we see that multi-argument functions are actually of the form:

```
f :: a -> ?
f = -- ...
```

And it’s entirely legal for that `?`

to be replaced with `(b -> ?)`

, and for
*that* `?`

to be replaced with `(c -> ?)`

and so on ad infinitum. Thus you have
*the appearance* of multi-argument functions.

As is common with Haskell, this results in what appears to be happy coincidence,
but is actually the product of developing a language on top of such a consistent
mathematical foundation. You’ll notice that after using `(<*>)`

on a function of
more than one argument, the result is not a wrapped result, but another wrapped
function – does that sound familiar? Exactly, it’s an applicative functor.

Let me say that again: if you supply a function of more than one argument and a
single wrapped value to `(<*>)`

, you end up with another applicative functor
which can be given to `(<*>)`

yet again with another wrapped value to supply the
remaining argument to that original function. This can continue as long as the
function needs more arguments. Exactly like normal function application.

## A “Concrete” Example ๐

Consider what this might look like if you start with a plain old function that (conceptually) takes more than one argument, but the values that it wants to operate on are wrapped in some container.

```
-- A normal function
f :: (a -> b -> c)
f = -- ...
-- One contained value, suitable for its first argument
x :: Applicative f => f a
x = -- ...
-- Another contained value, suitable for its second
y :: Applicative f => f b
y = -- ...
```

How do we pass `x`

and `y`

to `f`

to get some overall result? You wrap the
function with `pure`

then use `(<*>)`

repeatedly:

```
result :: Applicative f => f c
result = pure f <*> x <*> y
```

The first portion of that expression is very interesting: `pure f <*> x`

. What
is this bit doing? It’s taking a normal function and applying it to a contained
value. Wait a second, normal functors know how to do that!

Since in Haskell every `Applicative`

is also a `Functor`

, that means it could be
rewritten equivalently as `fmap f x`

, turning the whole expression into `fmap f x <*> y`

.

Never satisfied, Haskell introduced a function called `(<$>)`

which is just
`fmap`

but infix. With this alias, we can write:

```
result = f <$> x <*> y
```

Not only is this epically concise, but it looks exactly like `f x y`

which is
how this code would be written if there were no containers involved. Here we
have another, more powerful step towards the goal of writing code that has to
deal with some context (in our case, still that container) without actually
having to care about that context. You write your function like you normally
would, then add `(<$>)`

and `(<*>)`

between the arguments.

## What’s the Point? ๐

With all of this background knowledge, I came to a simple mental model for
applicative functors vs monads: *Monad is for series where Applicative is for
parallel*. This has nothing to do with concurrency or evaluation order, this is
only a concept I use to judge when a particular abstraction is better suited to
the problem at hand.

Let’s walk through a real example.

## Building a User ๐

In an application I’m working on, I’m doing OAuth based authentication. My domain has the following (simplified) user type:

```
data User = User
{ userFirstName :: Text
, userLastName :: Text
, userEmail :: Text
}
```

During the process of authentication, an OAuth endpoint provides me with some profile data which ultimately comes back as an association list:

```
type Profile = [(Text, Text)]
-- Example:
-- [ ("first_name", "Pat" )
-- , ("last_name" , "Brisbin" )
-- , ("email" , "me@pbrisbin.com")
-- ]
```

Within this list, I can find user data via the `lookup`

function which takes a
key and returns a `Maybe`

value. I had to write the function that builds a
`User`

out of this list of profile values. I also had to propagate any `Maybe`

values by returning `Maybe User`

.

First, let’s write this without exploiting the fact that `Maybe`

is a monad or
an applicative:

```
buildUser :: Profile -> Maybe User
buildUser p =
case lookup "first_name" p of
Nothing -> Nothing
Just fn -> case lookup "last_name" p of
Nothing -> Nothing
Just ln -> case lookup "email" p of
Nothing -> Nothing
Just e -> Just $ User fn ln e
```

Oof.

Treating `Maybe`

as a `Monad`

makes this much, much cleaner:

```
buildUser :: Profile -> Maybe User
buildUser p = do
fn <- lookup "first_name" p
ln <- lookup "last_name" p
e <- lookup "email" p
return $ User fn ln e
```

Up until a few weeks ago, I would’ve stopped there and been extremely proud of myself and Haskell. Haskell for supplying such a great abstraction for potential failed lookups, and myself for knowing how to use it.

Hopefully, the content of this blog post has made it clear that we can do better.

## Series vs Parallel ๐

Using `Monad`

means we have the ability to access the values returned by earlier
`lookup`

expressions in later ones. That ability is often critical, but not
always. In many cases (like here), we do nothing but pass them all as-is to the
`User`

constructor “at once” as a last step.

This is `Applicative`

, I know this.

```
-- f :: a -> b -> c -> d
User :: Text -> Text -> Text -> User
-- x :: f a
lookup "first_name" p :: Maybe Text
-- y :: f b
lookup "last_name" p :: Maybe Text
-- z :: f c
lookup "email" p :: Maybe Text
-- result :: f d
-- result = f <$> x <*> y <*> z
buildUser :: Profile -> Maybe User
buildUser p = User
<$> lookup "first_name" p
<*> lookup "last_name" p
<*> lookup "email" p
```

And now, I understand when to reach for `Applicative`

over `Monad`

. Perhaps you
do too?