As we saw in the previous one, Applicative allows to apply *n-ary* functions in a context. The context might be a parser, values that are potentially be errors, a list or a tree, optional values, IO actions, etc.

In my short learning experience so far, I've used it in practice for two things mostly.

Constructing values with data constructors that take several values. For example, those values would come from sequential parsers when working with parser combinators (like Parsec).

```
data User = User String String Int
-- "John Doe 26" -> User "John" "Doe" 26
parseUser :: Parser User
parseUser =
User <$> (parseWord <* whitespace)
<*> (parseWord <* whitespace)
<*> parseAge
parseWord :: Parser String
parseAge :: Parser Int
whitespace :: Parser () -- consumes as much whitespace as possible
-- Defined in Control.Applicative
(<*) :: Applicative f => f a -> f b -> f a
```

`(<*)`

is the lifted version of `const`

, here is something I wrote about that. As we can guess from the signature, in this case it applies both parses (ie. both consume input) but returns the first one, ignoring the second.

And the other use case, applying *n-ary* functions to values that might not be there. In other words, when the context is Either or Maybe.

```
add <$> (Just 1) <*> (Just 2) -- Just 3
add <$> Nothing <*> (Just 2) -- Nothing
add <$> (Just 1) <*> Nothing -- Nothing
add <$> Nothing <*> Nothing -- Nothing
add <$> (Right 1) <*> (Right 2) -- Right 3
add <$> (Left "err 1") <*> (Right 2) -- Left "err 1"
add <$> (Right 1) <*> (Left "err 2") -- Left "err 2"
add <$> (Left "err 1") <*> (Left "err 2") -- Left "err 1"
```

### Lists

Until last week I hadn't found a use case for Applicative when working with lists. I knew how it works but never had ~~an excuse~~ a reason to use it.

Let's take a look at the instance and some examples first.

```
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
-- With [] applied to f (using TypeApplications extension)
(<*>) @[] :: [a -> b] -> [a] -> [b]
(+) <$> [1, 2, 3] <*> [1, 2, 3]
-- [2,3,4,3,4,5,4,5,6]
(,) <$> [1, 2, 3] <*> [1, 2, 3]
-- [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
[(++ "!"), (++ "?")] <*> ["Hola", "Mundo"]
-- ["Hola!","Mundo!","Hola?","Mundo?"]
```

As we can see, it takes a list of functions (`[a -> b]`

) and a list values (`[a]`

) and applies all the functions from the first list to all the values from the second one, this results in a larger list (duh!). If list sizes are `n`

and `m`

, respectively, the size of the returned list is `n * m`

.

That's not a use case that I find very often. Most of the time I have one function (`a -> b`

) that I want to apply to a list of values (`[a]`

). That's Functor's `fmap`

(as well as `(<$>)`

). Or I have a list of functions to apply to a single value. For example, it could be list of predicates and I want to check if all or some are `True`

for a particular value.

```
allPass :: [a -> Bool] -> a -> Bool
anyPass :: [a -> Bool] -> a -> Bool
```

By the way, there are similar functions defined in Base:

```
and :: [Bool] -> Bool -- True when all are True
or :: [Bool] -> Bool -- True when at least one is True
```

In the case of lists, what applicative does is apply all the functions too all the values.

Last week, playing around on small side project, till. I was trying to add the option to match several patterns against the same value and I found a use case for List's Applicative.

There's a `match`

function that checks if a pattern matches a single line of the output.

```
match :: Pattern -> Line -> Bool
```

The output consists of a list of lines. When working with a single pattern, the solution is easy. Use any (from Base).

```
any :: Foldable t => (a -> Bool) -> t a -> Bool
any @[] :: (a -> Bool) -> [a] -> Bool
matchPattern :: Pattern -> [Line] -> Bool
matchPattern p lns = any (match p) lns
```

What about matching several patterns against the output?

```
matchAll :: [Pattern] -> [Line] -> Bool
matchAll ps lns = undefined -- ???
```

Applicative to the rescue ๐

```
matchAll :: [Pattern] -> [Line] -> Bool
matchAll ps lns = or (match <$> ps <*> lns)
```

Let's dissect that ๐

```
-- So we don't forget ;)
(<$>) @[] :: (a -> b) -> [a] -> [b]
(<*>) @[] :: [a -> b] -> [a] -> [b]
-- ^ notice the difference between <$> & <*> ;)
or :: [Bool] -> Bool
match :: Pattern -> Line -> Bool
-- the input
ps :: [Pattern]
lns :: [Line]
-- mapping first to partially apply the patterns to match
match <$> ps :: [Line -> Bool]
-- applying the lines
match <$> ps <*> lns :: [Bool]
-- reducing that to get our result
or (match <$> ps <*> lns) :: Bool
```

I like how elegant this looks thanks to Functor and Applicative ๐ฉ

*NOTE*: I'm sure there are other ways to solve the problem, with better performance. Although in my use case both lists *should* be relatively short, usually between one and three patterns and around 100 or probably less lines of output.

Happy and safe coding ๐ฆ

## Top comments (0)