Maintainer | diagrams-discuss@googlegroups.com |
---|
Various monoid-related definitions (monoid actions, split monoids, applicative monoids) used in the core diagrams library.
- class Action m s where
- act :: m -> s -> s
- data Split m
- split :: Monoid m => Split m
- data Forgetful m
- unForget :: Forgetful m -> m
- forget :: Monoid m => Forgetful m
- data Deletable m = Deletable Int m Int
- unDelete :: Deletable m -> m
- toDeletable :: m -> Deletable m
- deleteL :: Monoid m => Deletable m
- deleteR :: Monoid m => Deletable m
- newtype AM f m = AM (f m)
- inAM2 :: (f m -> f m -> f m) -> AM f m -> AM f m -> AM f m
- data m :+: n
- inL :: m -> m :+: n
- inR :: n -> m :+: n
- mappendL :: m -> (m :+: n) -> m :+: n
- mappendR :: n -> (m :+: n) -> m :+: n
- killL :: Monoid n => (m :+: n) -> n
- killR :: Monoid m => (m :+: n) -> m
- untangle :: (Action m n, Monoid m, Monoid n) => (m :+: n) -> (m, n)
Monoid actions
Type class for monoid actions, where monoidal values of type m
"act" on values of another type s
. Instances are required to
satisfy the laws
act mempty = id
act (m1 `
mappend
` m2) = act m1 . act m2
Additionally, if the type s
has any algebraic structure, act
m
should be a homomorphism. For example, if s
is also a
monoid we should have act m mempty = mempty
and act m (s1
`
.
mappend
` s2) = (act m s1) `mappend
` (act m s2)
By default, act = const id
, so for a monoidal type M
which
should have no action on anything, it suffices to write
instance Action M s
with no method implementations.
Action Name a | Names don't act on anything else. |
Action Nil l | |
Action Name (NameMap v) | A name acts on a name map by qualifying every name in it. |
Action m n => Action (Forgetful m) n | |
Action m n => Action (Split m) n | By default, the action of a split monoid is the same as for the underlying monoid, as if the split were removed. |
(v ~ V a, HasLinearMap v, Transformable a) => Action (Transformation v) a | Transformations can act on transformable things. |
Action (Style v) m | Styles have no action on other monoids. |
Monoid a => Action (SM a) Nil | |
(Action a a', Action (SM a) l) => Action (SM a) (::: a' l) | |
(Action m r, Action n r) => Action (:+: m n) r | Coproducts act on other things by having each of the components act individually. |
(Action m n, Foldable f, Functor f, Monoid n) => Action (AM f m) n | An applicative monoid acts on a value of a monoidal type by having each element in the structure act on the value independently, and then folding the resulting structure. |
(Monoid a, Action (SM a) l2, Action l1 l2) => Action (::: a l1) l2 |
Split monoids
Sometimes we want to accumulate values from some monoid, but have
the ability to introduce a "split" which separates values on
either side. For example, this is used when accumulating
transformations to be applied to primitive diagrams: the freeze
operation introduces a split, since only transformations occurring
outside the freeze should be applied to attributes.
A value of type Split m
is either a single m
, or a pair of
m
's separated by a divider.
split :: Monoid m => Split mSource
A convenient name for mempty :| mempty
, so a <> split <> b == a :| b
.
Forgetful monoids
Sometimes we want to be able to forget some information. We
define two monoid transformers that allow forgetting information.
Forgetful
introduces special values which cause anything to their
right to be forgotten. Deletable
introduces special left and
right bracket elements which cause everything inside them to be
forgotten.
A value of type Forgetful m
is either a "normal" value of
type m
, which combines normally with other normal values, or a
"forgetful" value, which combines normally with other values to
its left but discards values combined on the right. Also, when
combining a forgetful value with a normal one the result is
always forgetful.
Functor Forgetful | |
Monoid m => Monoid (Forgetful m) | If |
Transformable m => Transformable (Forgetful m) | |
Action m n => Action (Forgetful m) n |
forget :: Monoid m => Forgetful mSource
A convenient name for Forgetful mempty
, so a <> forget <>
b == Forgetful a
.
If m
is a Monoid
, then Deletable m
(intuitively speaking)
adds two distinguished new elements L and R, such that an
occurrence of L "deletes" everything from it to the next R. For
example,
abcLdefRgh == abcgh
This is all you really need to know to use Deletable m
values; to understand the actual implementation, read on.
To properly deal with nesting and associativity we need to be
able to assign meanings to things like LL
, RL
, and so on. (We
cannot just define, say, LL == L
, since then (LL)R == LR ==
id
but L(LR) == Lid == L
.) Formally, elements of Deletable
m
are triples of the form (r, m, l) representing words R^r m
L^l
. When combining two triples (r1, m1, l1) and (r2, m2, l2)
there are three cases:
- If l1 == r2 then the Ls from the left and Rs from the right exactly cancel, and we are left with (r1, m1 <> m2, l2).
- If l1 < r2 then all of the Ls cancel with some of the Rs, but m1 is still inside the remaining Rs and is deleted, yielding (r1 + r2 - l1, m2, l2)
- The remaining case is symmetric with the second.
Functor Deletable | |
Monoid m => Monoid (Deletable m) | |
Transformable m => Transformable (Deletable m) |
toDeletable :: m -> Deletable mSource
Applicative monoids
A wrapper for an Applicative
structure containing a monoid.
Such structures have a Monoid
instance based on "idiomatic"
application of mappend
within the Applicative
context.
instance Monoid m => Monoid (e -> m)
is one well-known special
case. (However, the standard Monoid
instance for Maybe
is
not an instance of this pattern; nor is the standard instance
for lists.)
AM (f m) |
Functor f => Functor (AM f) | |
Applicative f => Applicative (AM f) | |
(Applicative f, Monoid m) => Monoid (AM f m) | |
(Action m n, Foldable f, Functor f, Monoid n) => Action (AM f m) n | An applicative monoid acts on a value of a monoidal type by having each element in the structure act on the value independently, and then folding the resulting structure. |
inAM2 :: (f m -> f m -> f m) -> AM f m -> AM f m -> AM f mSource
Apply a binary function inside an AM
newtype wrapper.
Coproduct monoid
m :+: n
is the coproduct of monoids m
and n
. Values of
type m :+: n
consist of alternating lists of m
and n
values. The empty list is the identity, and composition is list
concatenation, with appropriate combining of adjacent elements
when possible.
killL :: Monoid n => (m :+: n) -> nSource
killL
takes a value in a coproduct monoid and sends all the
values from the left monoid to the identity.
killR :: Monoid m => (m :+: n) -> mSource
killR
takes a value in a coproduct monoid and sends all the
values from the right monoid to the identity.
untangle :: (Action m n, Monoid m, Monoid n) => (m :+: n) -> (m, n)Source
Take a value from a coproduct monoid where the left monoid has an action on the right, and "untangle" it into a pair of values. In particular,
m1 <> n1 <> m2 <> n2 <> m3 <> n3 <> ...
is sent to
(m1 <> m2 <> m3 <> ..., (act m1 n1) <> (act (m1 <> m2) n2) <> (act (m1 <> m2 <> m3) n3) <> ...)
That is, before combining n
values, every n
value is acted on
by all the m
values to its left.