# [diagrams] Monoidal annotations

Brent Yorgey byorgey at seas.upenn.edu
Thu Nov 18 17:49:06 EST 2010

```I wanted to write a quick note explaining a few patches I recently
pushed.  I got this idea from the graphics-drawingcombinators
library.  Diagrams are now generalized to annotated diagrams, which
have an extra type parameter:

data AnnDiagram b a = ...

b is still the type of the backend, a is the type of annotations.
There is a function

sample :: AnnDiagram b a -> BSpace b -> a

which means there is an annotation of type 'a' associated with each
point in the diagram's vector space.  'atop' combines the annotations
pointwise according to a Monoid instance for the annotations:

atop :: (Monoid a, ...) => AnnDiagram b a -> AnnDiagram b a -> AnnDiagram b a

Diagram is now a type synonym:

type Diagram b = AnnDiagram b Any

where Any is the monoid over Bool where mempty = False, mappend =
(||).  Every primitive diagram defines its sample function as a
predicate that tests whether the given vector lies in the diagram or
not.  Because of the Monoid instance for Any, combining multiple
primitive diagrams will correctly give you a sample function that
tests whether the given point lies in any of the primitive component
diagrams.

But you don't have to stick to Any.  (AnnDiagram b) is an instance of
Functor and Applicative, so you can do things like the following:

import qualified Data.Set as S

fromAny :: a -> a -> Any -> a
fromAny f _ (Any False) = f
fromAny _ t (Any True)  = t

withName :: String -> AnnDiagram b Any -> AnnDiagram b (S.Set String)
withName name = fmap \$ fromAny S.empty (S.singleton name)

myDia = withName "circle" circle `atop`
(withName "tri1" triangle `beside` withName "tri2" triangle)

(Assuming there are primitive diagrams 'circle' and 'triangle', and I
know that's not the right type for 'beside' but hopefully you get the
idea. =) Now 'sample myDia' is a function which for any given point,
gives us the set of names of all the primitive diagrams which occupy
that point.  Neat!

-Brent

```