-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Tree.DUAL
-- Copyright   :  (c) 2011-2012 Brent Yorgey
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Rose (n-ary) trees with both upwards- (/i.e./ cached) and
-- downwards-traveling (/i.e./ accumulating) monoidal annotations.
-- This is used as the core data structure underlying the @diagrams@
-- framework (<https://diagrams.github.io>), but potentially
-- has other applications as well.
--
-- Abstractly, a DUALTree is a rose (n-ary) tree with data (of type
-- @l@) at leaves, data (of type @a@) at internal nodes, and two types
-- of monoidal annotations, one (of type @u@) travelling \"up\" the
-- tree and one (of type @d@) traveling \"down\".
--
-- Specifically, there are five types of nodes:
--
--   * Leaf nodes which contain a data value of type @l@ and an
--     annotation of type @u@.  The annotation represents information
--     about a tree that should be accumulated (/e.g./ number of
--     leaves, some sort of \"weight\", /etc./).  If you are familiar
--     with finger trees
--     (<http://www.soi.city.ac.uk/~ross/papers/FingerTree.html>,
--     <http://hackage.haskell.org/package/fingertree>), it is the
--     same idea.
--
--   * There is also a special type of leaf node which contains only a
--     @u@ value, and no data. This allows cached @u@ values to be
--     \"modified\" by inserting extra annotations.
--
--   * Branch nodes, containing a list of subtrees.
--
--   * Internal nodes with a value of type @d@.  @d@ may have an
--     /action/ on @u@ (see the 'Action' type class, defined in
--     "Data.Monoid.Action" from the @monoid-extras@ package).
--     Semantically speaking, applying a @d@ annotation to a tree
--     transforms all the @u@ annotations below it by acting on them.
--     Operationally, however, since the action must be a monoid
--     homomorphism, applying a @d@ annotation can actually be done in
--     constant time.
--
--   * Internal nodes with data values of type @a@, possibly of a
--     different type than those in the leaves.  These are just \"along
--     for the ride\" and are unaffected by @u@ and @d@ annotations.
--
-- There are two critical points to note about @u@ and @d@ annotations:
--
--   * The combined @u@ annotation for an entire tree is always cached
--     at the root and available in constant (amortized) time.
--
--   * The 'mconcat' of all the @d@ annotations along the path from
--     the root to each leaf is available along with the leaf during a
--     fold operation.
--
-- A fold over a @DUALTree@ is given access to the internal and leaf
-- data, and the accumulated @d@ values at each leaf.  It is also
-- allowed to replace \"@u@-only\" leaves with a constant value.  In
-- particular, however, it is /not/ given access to any of the @u@
-- annotations, the idea being that those are used only for
-- /constructing/ trees.  It is also not given access to @d@ values as
-- they occur in the tree, only as they accumulate at leaves.  If you
-- do need access to @u@ or @d@ values, you can duplicate the values
-- you need in the internal data nodes.
--
-----------------------------------------------------------------------------

module Data.Tree.DUAL
       (
         -- * DUAL-trees
         DUALTree

         -- * Constructing DUAL-trees
       , empty, leaf, leafU, annot, applyD

         -- * Modifying DUAL-trees
       , applyUpre, applyUpost
       , mapU

         -- * Accessors and eliminators
       , getU, foldDUAL, flatten

       ) where

import Data.Tree.DUAL.Internal