| 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 | None |
| Language | Haskell2010 |
Control.Monad.Free.TH
Description
Automatic generation of free monadic actions.
Free monadic actions
$( provides free monadic actions for the
constructors of the given data type makeFree ''T)T.
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]
$( provides free monadic action for a data
constructor makeFreeCon 'Con)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:
- A type, perhaps depending on some of the
a1, …, aN. - A type dependent on
param, of the forms1 -> … -> sM -> param, M ≥ 0. At most 2 of thet1, …, tJmay be of this form. And, out of these two, at most 1 of them may haveM == 0; that is, be of the formparam.
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.
FooBarturns intofooBar). - 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:
- If no arguments to the constructor depend on
param,ret ≡ a, whereais a fresh type variable. - If only one argument in the constructor depends on
param, thenret ≡ (s1, …, sM). In particular, ifM == 0, thenret ≡ (); ifM == 1,ret ≡ s1. - If two arguments depend on
param, (e.g.u1 -> … -> uL -> paramandv1 -> … -> vM -> param, thenret ≡ 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 toret ≡ Maybe (u1, …, uL).ret ≡ Either () (v1, …, vM)is rewritten toret ≡ Maybe (v1, …, vM).