# Applicative Functors

This lecture is adjusted from Niki Vazou who adjusted from Ranjit Jhala who adjusted from Graham Hutton.

## Mapping Functions of Multiple Arguments

Thus far we have only dealt with mapping of single argument functions. However, there is no reason we can’t map a multiple argument function. For example, what do you think will be the type of `x`

after the following is executed?

Prelude> x = fmap (+) [1,2]

Recall that Haskell has currying, meaning that we can partially apply the two argument function `+`

with one argument.

Prelude> :t ((+) 1) ((+) 1) :: Num a => a -> a

Using this knowledge, for `x`

, we will get something that looks like this

x = [(+ 1),(+ 2)]

Indeed, if we check the type of `x`

, ghci tells us the type of `x`

is a list of functions from `a`

to `a`

where `a`

is an instance of the `Num`

typeclass:

Prelude> :t x x :: Num a => [a -> a]

## Motivating Applicative Functors

Let’s now consider a slightly different example. Let’s say we have two lists

Prelude> x = [1..5] Prelude> y = [101..105]

As discussed previously, let’s think of lists as representing nondeterminism. That is to say, `x`

represents a single value that could be any number 1 to 5, `y`

101 to 105. Let’s suppose we want to add these two nondeterministic values. We could try to use `fmap`

again.

Prelude> fmap (fmap (+) x) y <interactive>:31:7: error: • Couldn't match expected type ‘Integer -> b’ with actual type ‘[Integer -> Integer]’ • Possible cause: ‘fmap’ is applied to too many arguments In the first argument of ‘fmap’, namely ‘(fmap (+) x)’ In the expression: fmap (fmap (+) x) y In an equation for ‘it’: it = fmap (fmap (+) x) y • Relevant bindings include it :: [b] (bound at <interactive>:31:1)

Why didn’t this work? Well, let’s take a look at the types.

Prelude> :t fmap fmap :: Functor f => (a -> b) -> (f a -> f b) Prelude> :t (fmap (+) x) (fmap (+) x) :: (Enum a, Num a) => [a -> a]

Hmmm. `fmap`

expected a function from `a`

to `b`

but we gave it a function from list `a`

to `b`

. Hmmm, how can we get around this? Let’s take a step back and look at what `fmap`

does, per it’s type signature. We can think of `fmap`

as both 1) taking a function from `a`

s to `b`

s and an `f a`

and returning an `f b`

and 2) taking a function from `a`

s to `b`

s and returning a function from `f a`

s to `f b`

s. In this sense, we can think of `fmap`

as lifting a function from `a`

s to `b`

s to the context (functor) `f a`

s to `f b`

s.

Ok, well, can we write a function that would lift a function from `a`

s to `b`

s to `c`

s (like `+`

) to a particular functor context (like lists)? Let’s try to write such a function.

lift2 :: (a -> b -> c) -> [a] -> [b] -> [c] lift2 f xs ys = [ f x y | x <- xs, y <- ys]

Let’s see if it works.

Prelude> lift2 (+) x y [102,103,104,105,106,103,104,105,106,107,104, 105,106,107,108,105,106,107,108,109,106,107, 108,109,110]

Good, this performs our nondeterministic addition! But what about lifting a function that takes three arguments? Four? N? This seems like a place where currying might be nice.

Let’s define a typeclass to handle this.

class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b

The `Applicative`

typeclass has two functions `pure`

and `<*>`

. `pure`

takes a type `a`

and turns it into an `Applicative`

(and a `Functor`

). We can think of `pure`

as turning `a`

into a default instance of the `Applicative`

typeclass.

For `<*>`

, given an applicative function from `a`

to `b`

and an applicative `a`

, we get back an applicative `b`

.

Note first that for a type `f`

to be an instance of the `Applicative`

typeclass, it must also be an instance of the `Functor`

typeclass, meaning it has a defined `fmap`

function.

Why is this? It turns our every applicative is also a functor! How can we prove this? Well, if we can derive `fmap`

from our two functions, `pure`

and `<*>`

, we’re good. Let’s do that.

fmap' :: Applicative a => (b -> c) -> a b -> a c fmap' f x = pure f <*> x

Let’s look at the List instance of `Applicative`

.

instance Applicative [] where pure x = [x] fs <*> xs = [f x | f <- fs, x <- xs]

Notice `pure`

returns the singleton list as opposed to the empty list. While both would satisfy the type requirements of `pure`

, the empty list would ignore the argument `x`

to `pure`

which would be unusual (Note: while unusual, Haskell would allow this definition of `pure`

).

Ok, this is nice, but how do we get `lift2`

from this?

lift2' :: Applicative a => (b -> c -> d) -> (a b -> a c -> a d) lift2' f x y = (pure f) <*> x <*> y

And it works!

Prelude> (lift2' (+) x y) == (lift2 (+) x y) True

Ah-ha! What about `lift3`

?

lift3' :: Applicative a => (b -> c -> d -> e) -> (a b -> a c -> a d -> a e) lift3' f x y z = (pure f) <*> x <*> y <*> z

Nifty!

## Applicative Maybe

Let’s look at the `Maybe`

instance of the `Applicative`

typeclass.

instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing (Just g) <*> mx = fmap g mx

Let’s take a look at some examples to get a feel for how this works.

Prelude> pure (+1) <*> Just 1 Just 2 Prelude> pure (+) <*> Just 1 <*> Just 2 Just 3 Prelude> pure (+) <*> Nothing <*> Just 2 Nothing

Recall that we often use Nothing to represent failure/exception. That means the use of applicatives here can represent the propagation of exceptions -- error handling!

Let’s look at an example. Let’s first define a function `div’`

that divides two integers, returning the result, unless the denominator is zero, in which case it throws an error.

divv x y = if y == 0 then error "Denominator is 0!" else x / y

Here are some examples.

Prelude> divv 1 2 0.5 Prelude> divv 1 0 *** Exception: Denominator is 0! CallStack (from HasCallStack): error, called at <interactive>:30:31 in interactive:Ghci13

Hmmm, maybe we can use applicatives to define a safer division operator.

safeDivv x y = if y == 0 then Nothing else Just (x / y)

Now instead of crashing on divide by zero, we get Nothing.

Prelude> safeDivv 1 2 Just 0.5 Prelude> safeDivv 1 0 Nothing

Let’s try to do some arithmetic with our new safe division function.

Prelude> (safeDivv 1 2) + (safeDivv 4 0) <interactive>:73:1: error: • Non type-variable argument in the constraint: Num (Maybe a) (Use FlexibleContexts to permit this) • When checking the inferred type it :: forall a. (Num (Maybe a), Eq a, Fractional a) => Maybe a

Well that’s no good. Can we somehow make plus work for our new safe division without defining a whole new `safePlus`

function? Sure, with applicatives!

Prelude> pure (+) <*> (safeDivv 1 2) <*> (safeDivv 4 0) Nothing

Woah, cool! With applicatives we get `safePlus`

for free! And `safeTimes`

too!

## The Applicative Laws

Similar to functors, applicatives must also follow some laws, in this case four.

Identity:

pure id <*> v = v

Composition:

pure (.) <*> u <*> v <*> w = u <*> (v <*> w)

Identity:

pure f <*> pure x = pure (f x)

Identity:

u <*> pure y = pure ($ y) <*> u

I would not spend too long trying to digest these; they can be a bit challenging.

## Exercises for Home

Can you define the applicative instance for the Either typeclass?