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 |
Automatic generation of free monadic actions.
Free monadic actions
makeFree :: Name -> Q [ Dec ] Source #
$(
provides free monadic actions for the
constructors of the given data type
makeFree
''T)
T
.
makeFree_ :: Name -> Q [ Dec ] Source #
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 ] Source #
$(
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 ] Source #
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, …, tJ
may 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.
FooBar
turns 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
, wherea
is 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 -> param
andv1 -> … -> 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)
.