We have now seen several ways that we can use type classes
to defer implementation decisions about which equality type,
which collection type, or which monad type we will need in a
particular situation. These show up later as a collection of
class constraints in the inferred type. Of course, we do
eventually need to solve those constraints, but
it is useful to be able to treat generating and solving
constraints as separate concerns.
In some situations, we may still decide, ultimately, to
construct a single monad that can be used to satisfy the
constraints. However, it is often more flexible to build
a hierarchy of monads, with monad morphisms acting as
coercions between them. Such monads can be build using
adhoc methods, or more systematically using monad
transformers. The example on the slide here hints at how
classes may be used in the latter case to describe and
define specific monad transformers. Given an appropriate
set of monad transformers, we can satisfy a given set of
constraints by building a composite monad, repeatedly
transforming some base monad until all the constraints
are satisfied.
Next...
