Skip to content

Instantly share code, notes, and snippets.

@thsutton
Created August 8, 2014 00:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thsutton/3742b377d40e76a390c2 to your computer and use it in GitHub Desktop.
Save thsutton/3742b377d40e76a390c2 to your computer and use it in GitHub Desktop.
Monad transformers example - a monad with exceptions, logging, and configuration.
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main where
import Control.Applicative
import Control.Monad.Except
import Control.Monad.IO.Class ()
import Control.Monad.Reader
import Control.Monad.Writer
import Prelude hiding (log)
-- | Configuration.
data Config = Config
data Log = Log [String]
deriving (Show, Eq)
instance Monoid Log where
mempty = Log mempty
(Log m) `mappend` (Log n) = Log $ m `mappend` n
-- | Errors which can be raised.
data HandlerError = ERR
deriving (Show)
-- | Monad for handler actions.
newtype Handler a =
Handler {
unHandler :: ExceptT HandlerError (WriterT Log (ReaderT Config IO)) a
}
deriving (Applicative, Functor, Monad, MonadIO, MonadError HandlerError, MonadWriter Log)
runHandler :: Config -> Handler a -> IO (Either HandlerError a, Log)
runHandler c a = flip runReaderT c $ runWriterT $ runExceptT (unHandler a)
logMessage :: String -> Handler ()
logMessage msg = tell $ Log [msg]
logError :: HandlerError -> Handler ()
logError err = logMessage $ "Error: " ++ show err
attempt :: Handler ()
attempt = do
logMessage "Let's try"
throwError ERR
logMessage "But no"
createHandler :: Handler ()
createHandler = do
logMessage "Starting"
catchError attempt (logError)
logMessage "Stopping"
return ()
main :: IO ()
main = do
putStrLn "Hello!"
(res, log) <- runHandler Config createHandler
case res of
Left e -> print log
Right r -> print "YAY" >> print log
return ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment