Introducing Monads
The Functor, Applicative, and Monad typeclasses are pervasive across Haskell programs. These type classes help you address a wide variety of extremely common problems that arise when writing any number of real world programming problems.
You’ll learn about monads, applicatives, and functors and what laws govern them. You’ll also learn more about how to work with IO actions, and how to make use of other common data types, like the optional Maybe type.
You’ll be able to work effectively with any datatype that is a functor, applicative, or monad, and define your own instances for these type classes.
Throughout the remainder of this book we’ll make use of these typeclasses regularly.
Flipping the Script
Try to write instances of Functor, Applicative, and Monad for List where
Functor is defined in terms of Applicative, and Applicative is defined in
terms of Monad. Is this possible? Why or why not?
Hint 1
Some high level hint text
Hint 2
Some more detailed hint text
Hint 3
Even more detailed hint text
Solution
A complete solution for the exercise
Not a Functor
Imagine that we’ve created a new type to represent a sorted list of values:
{-# LANGUAGE DerivingStrategies #-}
module SortedListFunctor (SortedList, insertSorted) where
data SortedList a = Empty | Cons a (SortedList a)
  deriving stock (Eq, Show)
insertSorted :: Ord a => a -> SortedList a -> SortedList a
insertSorted a Empty = Cons a Empty
insertSorted a (Cons b bs)
  | a >= b = Cons b (insertSorted a bs)
  | otherwise = Cons a (Cons b bs)Although SortedList might be useful, it turns out that you can’t write a
correct instance of Functor for a SortedList. Try to define Functor
yourself and experiment with it’s behavior. See if you can figure out why you
can’t write a correct instance.
Hint 1
Some high level hint text
Hint 2
Some more detailed hint text
Hint 3
Even more detailed hint text
Solution
A complete solution for the exercise
The Extended Functor Family
In addition to the standard Functor class that you’ve used in this chapter,
there are other type classes that are related to Functor but with somewhat
different behaviors.
Bifunctors
A Bifunctor is like a Functor but even moreso, because a Bifunctor let’s
you map two different fields. The Bifunctor class is defined in
Data.Bifunctor. Let’s take a look at a definition for it:
class Bifunctor f where
  bimap :: (a -> c) -> (b -> d) -> f a b -> f c d
  first :: (a -> c) -> f a b -> f c b
  first f = bimap f id
  second :: (b -> d) -> f a b -> f a d
  second f = bimap id fTry to write an instance of Bifunctor for Either.
Contravariant Functors
The Contravariant class from Data.Functor.Contravariant in base defines a
_contravariant_ functor. Although we don’t normally refer to them this way,
the Functor class that you’ve been working with so far is a
class Contravariant f where
  contramap :: (b -> a) -> f a -> f bTry to create a new version of the Function type that you defined earlier, and
then write an instance of Contravariant for it. Can you also create an
instance of Contravariant for your original definition of Function? Why or
why not?
Profunctors
A Profunctor is a combination of a Bifunctor and a Contravariant
functor. Profunctor isn’t defined in base, but you’ll see it defined by some
other popular libraries. Like a Bifunctor it works on types with two
arguments. Like Contravariant functors, the first argument to a Profunctor
works “backwards”. Let’s take a look at a definition for Profunctor:
class Profunctor f where
  dimap :: (c -> a) -> (b -> d) -> f a b -> f c d
  lmap :: (c -> a) -> f a b -> f c b
  lmap f = dimap f id
  rmap :: (b -> d) -> f a b -> f a d
  rmap f = dimap id fTry to create an instance of Profunctor for your original Function type. Can
you write a valid instance? Why or why not? How does this differ from trying to
create a instance of Contravariant for Function?
Hint 1
Some high level hint text
Hint 2
Some more detailed hint text
Hint 3
Even more detailed hint text
Solution
A complete solution for the exercise