This series is focused on one important typeclass –
Applicative – and what applicative functors are. The series starts from a motivating example, a somewhat stripped-down version of something you might have encountered in “real code” and shows how the problem is solved with “
fmap plus a little something extra.” We go on to explore applicative functors in depth, working up to showing how the
Applicative class provides us with some useful tools for concurrency and parsing, among other tasks.
We also cover in this series two typeclasses that are closely related to
Traversable. If you have ever seen a Haskeller announce that “the answer is always
traverse” and wondered how that could possibly be even jokingly true, then this series is a great place to start.
- knowledge of basic types and also kinds;
- some comprehension of typeclasses and their relationship with types; and
- facility with Haskell syntax;
- a good understanding of
Inclusion in Prelude
For nearly a decade, these classes lived in their own separate modules:
Data.Traversable. Then in 2015, things took a dramatic turn when GHC 7.10.1 brought them all into the
Prelude module. The types of many
Prelude functions were changed to make use of these constraints. For example:
length :: [a] -> Int -- in GHC 7.8 length :: Foldable t => t a -> Int -- in GHC 7.10
This version also formalized the relationship between
Monad by introducing a new constraint: Every
Monad instance is now required to have a corresponding
class Monad m where -- in GHC 7.8 (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a class Applicative m => Monad m where -- in GHC 7.10 (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a
Maybethere’s a function – First we introduce a you might find in real everyday code: sometimes the function is embedded within a
Maybecontext because it might not be there. This is a problem
fmapalone can’t solve for us. We need an
fmapfor times when our function is stuck inside a constructor. But every problem is an opportunity to invent a solution, so we invent one. Then meet the typeclass that is designed for handling that situation in a general way,
Applicatives are monoidal! – This lesson starts with a comparison of different
Applicativeidioms and compares
(<*>). Then we look at product types as applicative functors and the connection between monoids and applicatives.
Sequencing effects – Here we take up with the rest of the
Applicativeclass, namely the so-called sequencing operators,
(<*). This leads us to consider carefully what is meant by effects when we talk about applicatives and gives us a new perspective on the connection, discussed in the previous lesson, of the connection between monoids and applicatives. We also give an example of applicative parsing techniques.
ZipList– Now you’re in for a surprise: lists are applicative functors in two ways. In this lesson we talk about why – which does lead us to talking about monoids again, just when you thought we were done with that!
Readercontext – This lesson revolves around a fun example: recruiter emails! As we did in the
Functorseries, we look at the function instance of
Applicativeas well as a
newtypewrapper for functions called
Readerand see how the applicative can make our tedious email chores more exciting.
Applicatives compose – The
Readernewtype is often combined with
IOin Haskell programs. Here we look at
Applicative, what it means to say that functors compose, and how to combine
IOto make a single powerful applicative functor.
Composenewtype – In this lesson, we continue working with the notion of applicative functor composition. Our goal here is to make it even more abstract and generalizable, and we introduce the
newtypeas one means of abstracting out the very notion of functor composition. We end the lesson with a look at a practical use of
An applicative Map – The way we have been discussing the
Applicativeclass as an extension of the basic idea of
Functormight have led you to believe that all
Applicatives but this is not the case. Here we’ll look at one important type,
Map, that is not, why it isn’t, and how we could make a “mappy” type that is