10
votes

I'm trying to learn monad transformers, based on the standard Haskell libraries (mtl? transformers? not sure which one came with my download of the Haskell platform - 7.4.1).

What I believe I've noticed is a common structure for each monad transformer definition:

  1. base type ('Base')

    • Monad instance
  2. transformer type ('BaseT')

    • Monad instance

    • MonadTrans instance

    • MonadIO instance

  3. transformer class ('MonadBase')

    • some operations

    • instances for other 'BaseT's

So for example, for the Writer monad, there'd be:

  • a Writer datatype/newtype/type, with a Monad instance
  • a WriterT datatype/newtype/type, with Monad, MonadTrans, and MonadIO instances
  • a MonadWriter class, and instances of this class for StateT, ReaderT, IdentityT, ...

Is this how monad transformers are organized? Am I missing anything/do I have any incorrect details?

The motivation for this question is figuring out:

  1. what the relationships and differences are between the "BaseT"s and the corresponding "MonadBase"s and "Base"s
  2. whether all three are required
  3. how MonadTrans is related and what its purpose is
1
Excellent resource on monads and transformers: monads.haskell.cz/html/index.htmlMatt Fenwick

1 Answers

4
votes

mtl package doesn't implement monad transformers. At least WriterT is just reexported from transformers.

transformers package implements WriterT, which is a monad transformer itself. Writer is just an alias:

type Writer w = WriterT w Identity

Some libraries can implement Writer separately, but anyway it is just a special case of WriterT. (Identity is a trivial monad, it doesn't have any additional behavior.)

MonadTrans allows you to wrap underlying monad into the transformed one. You can live without it, but you will need to perform manual wrapping (see MonadTrans instance definition for WriterT for example how to do it). The only use case where you really need MonadTrans -- when you don't know actual type of transformer.

MonadWriter is a type class declared in mtl. It's methods (writer, pass, tell and listen) are the same as function for WriterT. It allows to wrap (automatically!) WriterT computation through stack of transformers, even if you don't know exact types (and even number!) of transformers in the stack.

So, WriterT is the only type which is "required".

For other monad transformers it is the same: BaseT is a transformer, Base is a monad without underlying monad and MonadBase is a type class -- class of all monads, that have BaseT somewhere in transformers stack.

ADDED:

You can find great explanation in RWH book

Here is a basic example:

import Control.Monad.Trans
import Control.Monad.Trans.Writer
import Control.Monad.Trans.Reader hiding (ask)

-- `ask` from transformers
-- ask :: Monad m => ReaderT r m r
import qualified Control.Monad.Trans.Reader as TransReader (ask)

-- `ask` from mtl
-- ask :: MonadReader r m => m r
import qualified Control.Monad.Reader as MtlReader (ask)

-- Our monad transformer stack:
-- It supports reading Int and writing String
type M m a = WriterT String (ReaderT Int m) a

-- Run our monad
runM :: Monad m => Int -> M m a -> m (a, String)
runM i action = runReaderT (runWriterT action) i

test :: Monad m => M m Int
test = do
  tell "hello"
  -- v <- TransReader.ask     -- (I) will not compile
  v1 <- lift TransReader.ask  -- (II) ok
  v2 <- MtlReader.ask         -- (III) ok
  return (v1 + v2)

main :: IO ()
main = runM 123 test >>= print

Note that (I) will be rejected by compiler (try it to see the error message!). But (II) compiles, thanks to MonadTrans ("explicit lifting"). Thanks to MonadReader, (III) works out of the box ("implicit lifting"). Please read RWH book for explanation how it works.

(In the example we import ask from two different modules, that is why we need qualified import. Usually you will use only one of them at a time.)

Also I didn't mean to specifically ask about Writer.

Not sure I understand... Reader, State and others use the same schema. Replace Writer with State and you will have an explanation for State.