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
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
I'm not sure about
- Change the name of
- Change the name of
- 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.
- 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
type QDiagram b v m = Contextual b v m (RTree b v Annotation, Summary b v m)
Previously I had written:
It's important that this is NOT a newtype, so we can freely use the
Contextualwhen working with diagrams. This also means we don't need
Rewrappedinstances for it anymore. </blockquote However, making
newtypemeans we lose the
Functorinstance! Also, in the end, it's probably better that users do not need to know the underlying implementation. So we'll have to figure out some nice API/combinators for making use of the
All it needs to do is create a new
- The implementation of
applyAnnotationneeds to change.
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 -> RTreeetc.)
in this module will need to change as well. I'll walk through a few particular examples and then discuss more general principles. First,
- Of course the implementation of almost all the rest of the functions
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
UpAnnotsvalue, and uses it to create a leaf
DUALTree. Everything up through
UpAnnotsstill applies (though the name of
UpAnnotshas 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
leafSin parallel with
leafU: emptyTree = Node REmpty  leafS :: Summary b v m -> QDiagram b v m leafS s = return (emptyTree, s) Then the implementation of
pointDiagramonly needs to change to pointDiagram p = leafS (inj . toDeletable $ pointEnvelope p)
can't escape the
- The current type of
getU'can't work anymore, since we
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)
suitable replacements for
setEnvelope: the main issue here is to figure out
applyUPost. We could do applySPre :: Summary b v m -> QDiagram b v m -> QDiagram b v m applySPre s = (fmap . second) (s<>) But note we can also give this a much more general type signature like applyUPre :: (Functor f, Semigroup s) => s -> f (t,s) -> f (t,s) Not sure which is better. In any case, we don't need any of the
over _Wrappedstuff any more.
envelope :: forall b v m. (OrderedField (Scalar v), InnerSpace v , HasLinearMap v, Monoid' m) => Lens' (QDiagram b v m) (Envelope v) But this type won't work any more, because e.g. we can't simply extract an
envelopeis problematic. We had
QDiagram. I suppose we could do ... Lens' (QDiagram b v m) (Contextual b v m (Envelope v)) ?
- 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.
- What is a subdiagram in this context? Should it store a transformation along with a context? Are subdiagrams still needed at all? Yes, I think so. The reason we had subdiagrams storing DownAnnots was so that you could ask where a subdiagram "ended up" with respect to a parent diagram. For this you need to know the transformation that was applied to it.
2.1.2=== diagrams-lib ===