Control.Monad.Trans.Class

transformers-0.3.0.0: Concrete functor and monad transformers

Portability | portable
Stability | experimental
Maintainer | ross@soi.city.ac.uk
Safe Haskell | Safe-Inferred

Control.Monad.Trans.Class

Contents

- Transformer class
- Examples
  - Parsing
  - Parsing and counting

Description

Classes for monad transformers.

A monad transformer makes a new monad out of an existing monad, such that computations of the old monad may be embedded in the new one. To construct a monad with a desired set of features, one typically starts with a base monad, such as `Identity`, `[]` or `IO`, and applies a sequence of monad transformers.

Most monad transformer modules include the special case of applying the transformer to `Identity`. For example, `State s` is an abbreviation for `StateT s Identity`.

Each monad transformer also comes with an operation `run`XXX to unwrap the transformer, exposing a computation of the inner monad.

Synopsis

- class MonadTrans t where
  - lift :: Monad m => m a -> t m a

# Transformer class

class MonadTrans t where

The class of monad transformers. Instances should satisfy the following laws, which state that `lift` is a transformer of monads:

-     lift . return = return

-     lift (m >>= f) = lift m >>= (lift . f)

Methods

lift :: Monad m => m a -> t m a

Lift a computation from the argument monad to the constructed monad.

Instances

MonadTrans IdentityT |
MonadTrans ListT |
MonadTrans MaybeT |
MonadTrans (ContT r) |
Error e => MonadTrans (ErrorT e) |
MonadTrans (ReaderT r) |
MonadTrans (StateT s) |
MonadTrans (StateT s) |
Monoid w => MonadTrans (WriterT w) |
Monoid w => MonadTrans (WriterT w) |
Monoid w => MonadTrans (RWST r w s) |
Monoid w => MonadTrans (RWST r w s) |

# Examples

## Parsing

One might define a parsing monad by adding a state (the `String` remaining to be parsed) to the `[]` monad, which provides non-determinism:

     import Control.Monad.Trans.State

     type Parser = StateT String []

Then `Parser` is an instance of `MonadPlus`: monadic sequencing implements concatenation of parsers, while `mplus` provides choice. To use parsers, we need a primitive to run a constructed parser on an input string:

     runParser :: Parser a -> String -> [a]
     runParser p s = [x | (x, "") <- runStateT p s]

Finally, we need a primitive parser that matches a single character, from which arbitrarily complex parsers may be constructed:

     item :: Parser Char
     item = do
         c:cs <- get
         put cs
         return c

In this example we use the operations `get` and `put` from Control.Monad.Trans.State, which are defined only for monads that are applications of `StateT`. Alternatively one could use monad classes from the `mtl` package or similar, which contain methods `get` and `put` with types generalized over all suitable monads.

## Parsing and counting

We can define a parser that also counts by adding a `WriterT` transformer:

     import Control.Monad.Trans.Class
     import Control.Monad.Trans.State
     import Control.Monad.Trans.Writer
     import Data.Monoid

     type Parser = WriterT (Sum Int) (StateT String [])

The function that applies a parser must now unwrap each of the monad transformers in turn:

     runParser :: Parser a -> String -> [(a, Int)]
     runParser p s = [(x, n) | ((x, Sum n), "") <- runStateT (runWriterT p) s]

To define `item` parser, we need to lift the `StateT` operations through the `WriterT` transformers.

     item :: Parser Char
     item = do
         c:cs <- lift get
         lift (put cs)
         return c

In this case, we were able to do this with `lift`, but operations with more complex types require special lifting functions, which are provided by monad transformers for which they can be implemented. If you use the monad classes of the `mtl` package or similar, this lifting is handled automatically by the instances of the classes, and you need only use the generalized methods `get` and `put`.

We can also define a primitive using the Writer:

     tick :: Parser ()
     tick = tell (Sum 1)

Then the parser will keep track of how many `tick`s it executes.