In our introduction to monads, we showed
how some preexisting code was already monadic in form. Now that we are
beginning to grasp what a monad is and have seen the
typeclass, let’s build a monad with foreknowledge of what we’re doing.
We’ll start out by defining its interface, and then we’ll put it to use.
Once we have those out of the way, we’ll finally build it.
Pure Haskell code is wonderfully clean to write, but, of course, it can’t perform I/O. Sometimes, we’d like to have a record of decisions we made, without writing log information to a file. Let’s develop a small library to help with this.
globToRegex function that we developed in
Translating a glob Pattern into a Regular Expression. We will modify it so that it keeps a
record of each of the special pattern sequences that it translates. We
are revisiting familiar territory for a reason: it lets us compare
nonmonadic and monadic versions of the same code.
To start off, we’ll wrap our result type
Logger type constructor:
-- file: ch14/Logger.hs globToRegex :: String -> Logger String
We’ll intentionally keep the internals of the Logger module abstract:
-- file: ch14/Logger.hs module Logger ( Logger , Log , runLogger , record ) where
Hiding the details like this has two benefits: it grants us considerable flexibility in how we implement our monad, and more importantly, it gives users a simple interface.
Our Logger type is purely a type constructor. We don’t ...