This page describes the motivation and design for a refactoring of diagrams, to give them a semantics based on computing fixed points of functions from "context" information to raw tree of primitives together with some summary information.
See the original "manifesto" and ensuing mailing list discussion here: http://thread.gmane.org/gmane.comp.lang.haskell.diagrams/383
See also later IRC discussion beginning here: http://ircbrowse.net/browse/diagrams?events_page=935
2 Detailed design
Most of the changes should be in the
diagrams-core package, though a few things in
diagrams-lib may need to change as well.
No changes should be necessary to the following modules (all prefixed by
I'm not sure about
- Change the name of
- Change the name of
Context, and change its definition to
type Context b v m = Style v ::: Name ::: SubMap b v m ::: ()
The addition of
SubMap is so that we can use the positions of laid-out subdiagrams to compute the positions of others.
transfFromAnnotcan be deleted.
withQDiaLeafcan be deleted.
- Create new definitions
type ContextualT b v q m a = ReaderT (Context b v q) m a
type Contextual b v q a = ContextualT b v q Identity a
One could imagine making
newtype but that would necessitate writing lots of instances for things like
MonadReader, and so on.
- The definition of
QDiagramshould be changed to something like
type QDiagram b v m = Contextual b v m (RTree b v Annotation, Summary b v m)
It's important that this is NOT a newtype, so we can freely use the
Monad instance for
Contextual when working with diagrams. This also means we don't need
Rewrapped instances for it anymore.
- The implementation of
applyAnnotationneeds to change. All it needs to do is create a new
RAnnotnode), ignoring the context and having no effect on the summary. So something like
applyAnnotation an = fmap (first (Node (RAnnot an) . (:)))
We may end up having to do similar things in other situations so it may make sense to factor out parts of this into general utilities (e.g.
addRoot :: RNode -> RTree -> RTree etc.)
- Of course the implementation of almost all the rest of the functions in this module will need to change as well. I'll walk through a few particular examples and then discuss more general principles. First,
pointDiagram. The current code is
pointDiagram :: (Fractional (Scalar v), InnerSpace v) => Point v -> QDiagram b v m pointDiagram p = QD $ D.leafU (inj . toDeletable $ pointEnvelope p)
This creates a point envelope, wraps it in
Deletable, injects it into an
UpAnnots value, and uses it to create a leaf
DUALTree. Everything up through
UpAnnots still applies (though the name of
UpAnnots has changed). What's different is that we aren't creating an explicit tree with summary values at leaves; we simply return the summary value as part of the result of the diagram function. So we can create a function
leafS in parallel with
emptyTree = Node REmpty 
leafS :: Summary b v m -> QDiagram b v m leafS s = return (emptyTree, s)
Then the implementation of
pointDiagram only needs to change to
pointDiagram p = leafS (inj . toDeletable $ pointEnvelope p)
- The current type of
getU'can't work anymore, since we can't escape the
Contextualmonad. But we can have
getU' :: (Monoid u', u :>: u') => QDiagram b v m -> Contextual b v m u' getU' = fmap (option mempty id . get . snd)
- Name stuff: think about monad, etc.
withNames: should be able to simplify these to take advantage of monad. Don't need to have them in CPS anymore.