In the previous section, we saw how to hide the fact that we’re using a State monad to hold the state for our Supply monad.

Another important way to make code more
modular involves separating its *interface* (what the
code can do) from its *implementation*—how it does
it.

The standard random number generator in
`System.Random`

is known to be quite slow. If we use our
`randomsIO`

function to provide it
with random numbers, then our `next`

action will not perform well.

One simple and effective way that we could deal with this is to provide Supply with a better source of random numbers. Let’s set this idea aside, though, and consider an alternative approach, one that is useful in many settings. We will separate the actions we can perform with the monad from how it works using a typeclass:

-- file: ch15/SupplyClass.hs class (Monad m) => MonadSupply s m | m -> s where next :: m (Maybe s)

This typeclass defines the interface that any supply monad must implement. It bears careful inspection, since it uses several unfamiliar Haskell language extensions. We will cover each one in the sections that follow.

How should we read the snippet
`MonadSupply s m`

in the typeclass? If we add parentheses,
an equivalent expression is `(MonadSupply s) m`

, which is a
little clearer. In other words, given some type variable
`m`

that is a Monad, we can make it an
instance of the typeclass MonadSupply s. Unlike a regular
typeclass, this one has a *parameter*.

As this ...

Start Free Trial

No credit card required