Haskell Applicatives

Priyanka Mondal
3 min readApr 21, 2020

I hope that anyone who is reading this is familiar with Haskell typeclasses and functors.

Applicatives are functors but with more power. Applicatives are sometimes called Applicative functors.

In functors we have seen that the values are wrapped in type constructors. In case of applicatives, functions are also wrapped in a constructor.

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

The definition of Applicative class says that any type constructor, f, that is an Applicative instance has to be a functor first (i.e. fmap can be used on it). Applicative has two function definitions, pure and <*>. pure takes a value of type a and returns a wrapped inside applicative instance f, i.e. returns f a. <*> function resembles with fmap.

Let us have a look at Maybe applicative.

instance Applicative Maybe where
pure a = Just a
Nothing <*> _ = Nothing
(Just func) <*> something = fmap func something

Because this is an instance of Maybe Applicative, we need to define pure and <*> functions for it. And we know Maybe has to be a functor already, so fmap can be applied on it. As defined above pure function wraps its type parameter within an applicative. In this case, it uses the default value constructor, Just. Next we have to define the <*> function. We know <*> takes a wrapped function and a wrapped value and returns a wrapped value. Maybe has two value constructors. Nothing has nothing inside it. So there is no way we can get a function of the (a->b) form inside it. So irrespective of the second parameter to <*> function, returning Nothing is the only smart choice. When one of the parameters to <*> is (Just func) value, then we know that this func is a function of the form (a->b). and the second parameter is a value wrapped inside an applicative (For Maybe it can be either Nothing, or it can be Just v, for some value v of type a). The definition says that the function func is unwrapped and famp is applied on func and the wrapped value (which is something ). From the definition of fmap ( fmap definition for Maybe functor is shown below ) we know that fmap can handle this.

instance Functor Maybe where
fmap f (Just x) = Just(f x)
fmap f Nothing = Nothing

One question might bother us! Why do we need applicatives when we have functors ? What is so great we are achieving with applicatives?

Functors allow you to map a function over a functor. Applicative functors allow you to work on several functors with a single function. Let us see an example -

ghci > pure (+) <*> Just 8 <*> Just 4
Just

On the other hand, the following example gives error.

ghci > fmap (+) (Just 3)
**error**
ghci> fmap (+3) (Just 3)
Just 6

“Armed with<$> and <*>, applicatives can take any function that expects any number of unwrapped values. Then it passes it all wrapped values, and it gets a wrapped value out!” where <$> is infix operator for fmap.

List can be an instance of applicatives. Here is how.

instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]
ghci> [(+2),(*1),(^0)] <*> [2,7,1]
[4,9,3,2,7,1,1,1,1]

Why the first one works fine and the second one gives an error?

ghci> (*) <$> Just 5 <*> Just 3
Just 15
ghci> fmap (*) Just 5 <*> Just 3
**error**

--

--