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
- 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. In
particular, we can introduce special Forgetful
values which cause
anything to their right 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
.
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.