free-5.2: Monads for free

Copyright | (C) 2008-2013 Edward Kmett
License | BSD-style (see the file LICENSE)
Maintainer | Edward Kmett <ekmett@gmail.com>
Stability | provisional
Portability | MPTCs, fundeps
Safe Haskell | Safe
Language | Haskell2010

Control.Monad.Free.TH

Contents

- Free monadic actions
- Documentation
- Examples

Description

Automatic generation of free monadic actions.

Synopsis

- makeFree :: Name -> Q [Dec]
- makeFree_ :: Name -> Q [Dec]
- makeFreeCon :: Name -> Q [Dec]
- makeFreeCon_ :: Name -> Q [Dec]

# Free monadic actions

makeFree :: Name -> Q [Dec] #

`$(`makeFree` ''T)` provides free monadic actions for the constructors of the given data type `T`.

makeFree_ :: Name -> Q [Dec] #

Like `makeFree`, but does not provide type signatures. This can be used to attach Haddock comments to individual arguments for each generated function.

    data LangF x = Output String x

    makeFree_ 'LangF

    -- | Output a string.
    output :: MonadFree LangF m =>
              String   -- ^ String to output.
           -> m ()     -- ^ No result.

`makeFree_` must be called *before* the explicit type signatures.

makeFreeCon :: Name -> Q [Dec] #

`$(`makeFreeCon` 'Con)` provides free monadic action for a data constructor `Con`. Note that you can attach Haddock comment to the generated function by placing it before the top-level invocation of `makeFreeCon`:

    -- | Output a string.
    makeFreeCon 'Output

makeFreeCon_ :: Name -> Q [Dec] #

Like `makeFreeCon`, but does not provide a type signature. This can be used to attach Haddock comments to individual arguments.

    data LangF x = Output String x

    makeFreeCon_ 'Output

    -- | Output a string.
    output :: MonadFree LangF m =>
              String   -- ^ String to output.
           -> m ()     -- ^ No result.

`makeFreeCon_` must be called *before* the explicit type signature.

# Documentation

To generate free monadic actions from a `Type`, it must be a `data` declaration (maybe GADT) with at least one free variable. For each constructor of the type, a new function will be declared.

Consider the following generalized definitions:

    data Type a1 a2 … aN param = …
                               | FooBar t1 t2 t3 … tJ
                               | (:+) t1 t2 t3 … tJ
                               | t1 :* t2
                               | t1 `Bar` t2
                               | Baz { x :: t1, y :: t2, …, z :: tJ }
                               | forall b1 b2 … bN. cxt => Qux t1 t2 … tJ
                               | …

where each of the constructor arguments `t1, …, tJ` is either:

1. A type, perhaps depending on some of the `a1, …, aN`.
2. A type dependent on `param`, of the form `s1 -> … -> sM -> param`, M ≥ 0. At most 2 of the `t1, …, tJ` may be of this form. And, out of these two, at most 1 of them may have `M == 0`; that is, be of the form `param`.

For each constructor, a function will be generated. First, the name of the function is derived from the name of the constructor:

- For prefix constructors, the name of the constructor with the first letter in lowercase (e.g. `FooBar` turns into `fooBar`).
- For infix constructors, the name of the constructor with the first character (a colon `:`), removed (e.g. `:+` turns into `+`).

Then, the type of the function is derived from the arguments to the constructor:

    …
    fooBar :: (MonadFree Type m) => t1' -> … -> tK' -> m ret
    (+)    :: (MonadFree Type m) => t1' -> … -> tK' -> m ret
    bar    :: (MonadFree Type m) => t1  -> … -> tK' -> m ret
    baz    :: (MonadFree Type m) => t1' -> … -> tK' -> m ret
    qux    :: (MonadFree Type m, cxt) => t1' -> … -> tK' -> m ret
    …

The `t1', …, tK'` are those `t1` … `tJ` that only depend on the `a1, …, aN`.

The type `ret` depends on those constructor arguments that reference the `param` type variable:

1. If no arguments to the constructor depend on `param`, `ret ≡ a`, where `a` is a fresh type variable.
2. If only one argument in the constructor depends on `param`, then `ret ≡ (s1, …, sM)`. In particular, if `M == 0`, then `ret ≡ ()`; if `M == 1`, `ret ≡ s1`.
3. If two arguments depend on `param`, (e.g. `u1 -> … -> uL -> param` and `v1 -> … -> vM -> param`, then `ret ≡ Either (u1, …, uL) (v1, …, vM)`.

Note that `Either a ()` and `Either () a` are both isomorphic to `Maybe a`. Because of this, when `L == 0` or `M == 0` in case 3., the type of `ret` is simplified:

- `ret ≡ Either (u1, …, uL) ()` is rewritten to `ret ≡ Maybe (u1, …, uL)`.
- `ret ≡ Either () (v1, …, vM)` is rewritten to `ret ≡ Maybe (v1, …, vM)`.

# Examples

Teletype (regular data type declaration)

Retry (GADT declaration)