packages feed

fixplate (empty) → 0.1

raw patch · 14 files changed

+1593/−0 lines, 14 filesdep +QuickCheckdep +basesetup-changed

Dependencies added: QuickCheck, base

Files

+ Data/Generics/Fixplate.hs view
@@ -0,0 +1,76 @@+
+-- | This library provides Uniplate-style generic traversals for fixed-point types.
+-- The advantages of using fixed-point types instead of explicit recursion are the following:
+--
+--   * we can add attributes to the nodes of an existing tree;
+--
+--   * there is no need for a custom type class, we can build everything on the top of
+--     @Functor@, @Foldable@ and @Traversable@, for which GHC can derive the instances for us;
+--
+--   * some operations can retain the structure of the tree, instead flattening
+--     it into a list;
+--
+--   * it is quite straightforward to provide a generic zipper.
+--
+-- The main disadvantage is that it does not work well for
+-- mutually recursive data types, and that pattern matching becomes
+-- more tedious (but there are solutions for the latter).
+--
+-- Consider as an example the following simple expression language,
+-- encoded by a recursive algebraic data type:
+--
+-- > Expr 
+-- >   = Kst Int 
+-- >   | Var String 
+-- >   | Add Expr Expr
+-- >   deriving (Eq,Show)
+--
+-- We can open up the recursion, and obtain a /functor/ instead:
+--
+-- > Expr1 e 
+-- >   = Kst Int 
+-- >   | Var String 
+-- >   | Add e e 
+-- >   deriving (Eq,Show,Functor,Foldable,Traversable)
+--
+-- The fixed-point type 'Mu'@ Expr1@ is isomorphic to @Expr@.
+-- However, we can also add some attributes to the nodes:
+-- The type 'Attr' @Expr1 a = @'Mu'@ (@'Ann'@ Expr1 a)@ is the type of
+-- with the same structure, but with each node having an extra
+-- field of type @a@.
+--
+-- The functions in this library work on types like that: 'Mu'@ f@,
+-- where @f@ is a functor, and sometimes explicitely on 'Attr'@ f a@.
+-- 
+-- This module re-exports all the functionality present in the library.
+--
+-- The library is fully Haskell98 compatible, with the exception
+-- of the module "Data.Generics.Fixplate.Structure", which needs
+-- the @Rank2Types@ extension. For compatibility, this functionality
+-- of this module is at the moment only provided when compiled with GHC.
+--
+module Data.Generics.Fixplate 
+  ( module Data.Generics.Fixplate.Base
+  , module Data.Generics.Fixplate.Traversals
+  , module Data.Generics.Fixplate.Morphisms
+  , module Data.Generics.Fixplate.Attributes
+  , module Data.Generics.Fixplate.Zipper
+  , module Data.Generics.Fixplate.Structure
+  , Functor(..) , Foldable(..) , Traversable(..)
+  )
+  where
+  
+--------------------------------------------------------------------------------
+  
+import Data.Generics.Fixplate.Base
+import Data.Generics.Fixplate.Traversals
+import Data.Generics.Fixplate.Morphisms
+import Data.Generics.Fixplate.Attributes
+import Data.Generics.Fixplate.Zipper
+import Data.Generics.Fixplate.Structure  
+
+import Data.Foldable
+import Data.Traversable
+
+--------------------------------------------------------------------------------
+
+ Data/Generics/Fixplate/Attributes.hs view
@@ -0,0 +1,159 @@+
+-- | Synthetising attributes, motivated by Attribute Grammars.
+
+{-# LANGUAGE CPP #-}
+module Data.Generics.Fixplate.Attributes
+  ( toList
+  , Attrib(..)
+  -- * Synthetised attributes
+  , synthetise , synthetise' , synthetiseList , synthetiseM
+  -- * Inherited attributes
+  , inherit , inherit'
+  -- * Traversals
+  , synthAccumL  , synthAccumR
+  , synthAccumL_ , synthAccumR_
+  , numberNodes  , numberNodes_
+#ifdef WITH_QUICKCHECK
+  -- * Tests
+  , runtests_Attributes  
+  , prop_synthAccumL
+  , prop_synthAccumR
+  , prop_synthetise
+#endif  
+  )
+  where
+
+--------------------------------------------------------------------------------
+
+import Control.Monad (liftM)
+import Data.Foldable
+import Data.Traversable
+import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap,sum)
+
+import Data.Generics.Fixplate.Base
+
+#ifdef WITH_QUICKCHECK
+import Test.QuickCheck
+import Data.Generics.Fixplate.Traversals
+import Data.Generics.Fixplate.Test.Tools
+#endif 
+
+--------------------------------------------------------------------------------
+-- Synthetised attributes
+
+-- | /Synthetised/ attributes are created in a bottom-up manner. 
+-- As an example, the @sizes@ function computes the sizes of all
+-- subtrees:
+--
+-- > sizes :: (Functor f, Foldable f) => Mu f -> Attr f Int
+-- > sizes = synthetise (\t -> 1 + sum t)
+--
+-- (note that @sum@ here is @Data.Foldable.sum == Prelude.sum . Data.Foldable.toList@)
+--
+synthetise :: Functor f => (f a -> a) -> Mu f -> Attr f a
+synthetise h = go where
+  go (Fix x) = Fix $ Ann (h a) y where 
+    y  =  fmap go x  
+    a  =  fmap attribute y
+ 
+-- | Generalization of @scanr@ for trees.
+synthetise' :: Functor f => (a -> f b -> b) -> Attr f a -> Attr f b
+synthetise' h = go where
+  go (Fix (Ann b x)) = Fix $ Ann (h b a) y where 
+    y  =  fmap go x  
+    a  =  fmap attribute y
+
+synthetiseList :: (Functor f, Foldable f) => ([a] -> a) -> Mu f -> Attr f a
+synthetiseList h = synthetise (h . toList)
+
+synthetiseM  ::  (Traversable f, Monad m) =>  (f a -> m a) -> Mu f -> m (Attr f a)
+synthetiseM act = go where
+  go (Fix x) = do
+    y  <-  mapM go x    
+    a  <-  act $ fmap attribute y
+    return (Fix (Ann a y))
+
+--------------------------------------------------------------------------------
+-- Inherited attributes
+
+-- | /Inherited/ attributes are created in a top-down manner. 
+-- As an example, the @depths@ function computes the depth 
+-- (the distance from the root, incremented by 1) of all subtrees:
+--
+-- > depths :: Functor f => Mu f -> Attr f Int
+-- > depths = inherit (\_ i -> i+1) 0
+--
+inherit :: Functor f => (Mu f -> a -> a) -> a -> Mu f -> Attr f a
+inherit h root = go root where
+  go p s@(Fix t) = let a = h s p in Fix (Ann a (fmap (go a) t))
+
+-- | Generalization of @scanl@ for trees
+inherit' :: Functor f => (a -> b -> a) -> a -> Attr f b -> Attr f a
+inherit' h root = go root where
+  go p (Fix (Ann a t)) = let b = h p a in Fix (Ann b (fmap (go b) t))
+
+--------------------------------------------------------------------------------
+-- Traversals
+
+-- | Synthetising attributes via an accumulating map in a left-to-right fashion
+-- (the order is the same as in @foldl@).
+synthAccumL :: Traversable f => (a -> Mu f -> (a,b)) -> a -> Mu f -> (a, Attr f b)
+synthAccumL h x0 tree = go x0 tree where
+  go x t@(Fix sub) = 
+    let (y,a   ) = h x t 
+        (z,sub') = mapAccumL go y sub
+    in (z, Fix (Ann a sub'))
+
+-- | Synthetising attributes via an accumulating map in a right-to-left fashion
+-- (the order is the same as in @foldr@).
+synthAccumR :: Traversable f => (a -> Mu f -> (a,b)) -> a -> Mu f -> (a, Attr f b)
+synthAccumR h x0 tree = go x0 tree where
+  go x t@(Fix sub) = 
+    let (y,sub') = mapAccumR go x sub
+        (z,a   ) = h y t 
+    in (z, Fix (Ann a sub'))
+    
+synthAccumL_ :: Traversable f => (a -> Mu f -> (a,b)) -> a -> Mu f -> Attr f b
+synthAccumL_ h x t = snd (synthAccumL h x t)
+
+synthAccumR_ :: Traversable f => (a -> Mu f -> (a,b)) -> a -> Mu f -> Attr f b
+synthAccumR_ h x t = snd (synthAccumR h x t)
+
+-- | We use 'synthAccumL' to number the nodes from @0@ to @(n-1)@ in 
+-- a left-to-right traversal fashion, where
+-- @n == length (universe tree)@ is the number of substructures,
+-- which is also returned.
+numberNodes :: Traversable f => Mu f -> (Int, Attr f Int)
+numberNodes tree = synthAccumL (\i _ -> (i+1,i)) 0 tree
+
+numberNodes_ :: Traversable f => Mu f -> Attr f Int
+numberNodes_ = snd . numberNodes
+
+--------------------------------------------------------------------------------
+-- Tests
+#ifdef WITH_QUICKCHECK
+
+runtests_Attributes = do
+  quickCheck prop_synthAccumL
+  quickCheck prop_synthAccumR
+  quickCheck prop_synthetise
+ 
+prop_synthAccumL :: FixT Label -> Bool
+prop_synthAccumL tree = 
+  toList (Attrib (synthAccumL_ (\i _ -> (i+1,i)) 1 tree)) == [1..length (universe tree)]
+
+prop_synthAccumR :: FixT Label -> Bool
+prop_synthAccumR tree = 
+  toList (Attrib (synthAccumR_ (\i _ -> (i+1,i)) 1 tree)) == reverse [1..length (universe tree)]
+
+prop_synthetise :: FixT Label -> Bool
+prop_synthetise tree = 
+  map attribute (universe $ synthetise (\(TreeF (Label l) xs) -> l ++ concat xs) tree)
+  ==
+  map fold (universe tree)
+  where
+    fold = foldLeft (\s (Fix (TreeF (Label l) _)) -> s++l) []
+  
+#endif
+--------------------------------------------------------------------------------
+
+ Data/Generics/Fixplate/Base.hs view
@@ -0,0 +1,177 @@+
+{-# LANGUAGE CPP #-}
+
+-- | The core types of Fixplate.
+module Data.Generics.Fixplate.Base where
+
+--------------------------------------------------------------------------------
+
+import Control.Applicative
+import Control.Monad (liftM)
+import Data.Foldable
+import Data.Traversable
+import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap)
+
+import Text.Show
+import Text.Read
+
+import Data.Generics.Fixplate.Misc
+
+--------------------------------------------------------------------------------
+
+-- | The attribute of the root node.
+attribute :: Attr f a -> a
+attribute = attr . unFix
+  
+-- | A function forgetting all the attributes from an annotated tree.
+forget :: Functor f => Attr f a -> Mu f
+forget = Fix . fmap forget . unAnn . unFix
+
+--------------------------------------------------------------------------------
+
+-- | The fixed-point type.
+newtype Mu f = Fix { unFix :: f (Mu f) }
+
+-- | Annotations.
+data Ann f a b  =  Ann { attr :: a , unAnn :: f b }
+
+-- | Annotated fixed-point type.
+type Attr f a   =  Mu (Ann f a)
+
+--------------------------------------------------------------------------------
+
+-- | \"Functorised\" versions of standard type classes. 
+-- If you have your own structure functor, for example
+--
+-- > Expr e 
+-- >   = Kst Int 
+-- >   | Var String 
+-- >   | Add e e 
+-- >   deriving (Eq,Ord,Read,Show,Functor,Foldable,Traversable)
+--
+-- you should make it an instance of these, so that the 
+-- fixed-point type @Mu Expr@ can be an instance of
+-- @Eq@, @Ord@ and @Show@. Doing so is very easy:
+--
+-- > instance EqF   Expr where equalF     = (==)
+-- > instance OrdF  Expr where compareF   = compare
+-- > instance ShowF Expr where showsPrecF = showsPrec
+--
+-- The @Read@ instance depends on whether we are using GHC or not.
+-- The Haskell98 version is
+--
+-- > instance ReadF Expr where readsPrecF = readsPrec
+--
+-- while the GHC version is
+--
+-- > instance ReadF Expr where readPrecF  = readPrec
+--
+class          EqF   f  where equalF     ::  Eq   a  =>  f a -> f a -> Bool
+class EqF f => OrdF  f  where compareF   ::  Ord  a  =>  f a -> f a -> Ordering
+class          ShowF f  where showsPrecF ::  Show a  =>  Int -> f a -> ShowS
+class          ReadF f  where 
+#ifdef __GLASGOW_HASKELL__
+                              readPrecF  ::  Read a  =>  ReadPrec (f a)
+#else
+                              readsPrecF ::  Read a  =>  Int -> ReadS (f a)                              
+#endif                        
+      
+--------------------------------------------------------------------------------
+
+instance EqF f => Eq (Mu f) where Fix x == Fix y = equalF x y
+instance OrdF   f  => Ord   (Mu f) where compare (Fix x) (Fix y)  = compareF x y
+instance ShowF  f  => Show  (Mu f) where 
+  showsPrec d (Fix x) = showParen (d>app_prec) 
+    $ showString "Fix " 
+    . showsPrecF (app_prec+1) x
+
+instance ReadF  f  => Read  (Mu f) where     
+#ifdef __GLASGOW_HASKELL__
+  readPrec = parens $ 
+    (prec app_prec $ do
+      { Ident "Fix" <- lexP
+      ; m <- step readPrecF
+      ; return (Fix m)            
+      })
+#else                                  
+  readsPrec d r = readParen (d > app_prec)
+     (\r -> [ (Fix m, t) 
+            | ("Fix", s) <- lex r
+            , (m,t) <- readsPrecF (app_prec+1) s]) r    
+#endif
+            
+--------------------------------------------------------------------------------
+        
+instance (Eq a, EqF f) => EqF (Ann f a) where 
+  equalF (Ann a x) (Ann b y) = a == b && equalF x y
+
+instance (Ord a, OrdF f) => OrdF (Ann f a) where 
+  compareF (Ann a x) (Ann b y) = case compare a b of
+    LT -> LT
+    GT -> GT
+    EQ -> compareF x y
+  
+instance (Show a, ShowF f) => ShowF (Ann f a) where 
+  showsPrecF d (Ann a t) 
+    = showParen (d>app_prec) 
+      $ showString "Ann " 
+      . (showsPrec (app_prec+1) a) 
+      . showChar ' ' 
+      . (showsPrecF (app_prec+1) t)    
+
+instance (Read a, ReadF f) => ReadF (Ann f a) where 
+#ifdef __GLASGOW_HASKELL__
+  readPrecF = parens $ 
+    (prec app_prec $ do
+      { Ident "Ann" <- lexP
+      ; x <- step readPrec
+      ; m <- step readPrecF
+      ; return (Ann x m)            
+      })
+#else                                  
+  readsPrecF d r = readParen (d > app_prec)
+     (\r -> [ (Ann x m, u) 
+            | ("Ann", s) <- lex r
+            , (x,t) <- readsPrec  (app_prec+1) s]) r    
+            , (m,u) <- readsPrecF (app_prec+1) t]) r    
+#endif
+      
+--------------------------------------------------------------------------------
+
+instance Functor f => Functor (Ann f a) where
+  fmap f (Ann attr t) = Ann attr (fmap f t)
+
+instance Foldable f => Foldable (Ann f a) where
+  foldl f x (Ann _ t) = foldl f x t
+  foldr f x (Ann _ t) = foldr f x t
+
+instance Traversable f => Traversable (Ann f a) where
+  traverse f (Ann x t) = Ann x <$> traverse f t
+  mapM f (Ann x t) = liftM (Ann x) (mapM f t)
+ 
+--------------------------------------------------------------------------------
+
+-- | A newtype wrapper around @Attr f a@ so that we can make @Attr f@ 
+-- an instance of Functor, Foldable and Traversable. This is necessary
+-- since Haskell does not allow partial application of type synonyms.
+newtype Attrib f a = Attrib { unAttrib :: Attr f a }
+
+instance (ShowF f, Show a) => Show (Attrib f a) where
+  showsPrec d (Attrib x) 
+    = showParen (d>app_prec) 
+      $ showString "Attrib " 
+      . (showsPrec (app_prec+1) x) 
+
+instance Functor f => Functor (Attrib f) where
+  fmap h (Attrib y) = Attrib (go y) where
+    go (Fix (Ann x t)) = Fix $ Ann (h x) (fmap go t)
+
+instance Foldable f => Foldable (Attrib f) where
+  foldl h a (Attrib y) = go a y where go b (Fix (Ann x t)) = foldl go (h b x) t
+  foldr h a (Attrib y) = go y a where go (Fix (Ann x t)) b = h x (foldr go b t)
+
+instance Traversable f => Traversable (Attrib f) where
+  traverse h (Attrib y) = Attrib <$> go y where
+    go (Fix (Ann x t)) = Fix <$> (Ann <$> h x <*> traverse go t)
+
+--------------------------------------------------------------------------------
+ Data/Generics/Fixplate/Misc.hs view
@@ -0,0 +1,60 @@+
+-- | Miscellaneous utility functions
+module Data.Generics.Fixplate.Misc where
+
+--------------------------------------------------------------------------------
+
+import Data.Traversable
+
+--------------------------------------------------------------------------------
+
+mapAccumL_ :: Traversable f => (a -> b -> (a, c)) -> a -> f b -> f c
+mapAccumL_ f x t = snd (mapAccumL f x t)
+
+--------------------------------------------------------------------------------
+        
+data Two a b 
+  =  Empty 
+  |  One a
+  |  Two b
+
+--------------------------------------------------------------------------------
+
+unsafe :: (a -> Maybe b) -> String -> a -> b
+unsafe safe msg loc = case safe loc of
+  Just new -> new
+  Nothing  -> error msg
+  
+--------------------------------------------------------------------------------
+
+app_prec :: Int
+app_prec = 10
+
+--------------------------------------------------------------------------------
+
+(<#>) :: (a -> b) -> (c -> d) -> (a,c) -> (b,d)
+(f <#> g) (x,y) = (f x, g y)
+
+--------------------------------------------------------------------------------
+
+tillNothing :: (a -> Maybe a) -> a -> a
+tillNothing f = go where 
+  go x = case f x of { Nothing -> x ; Just y -> go y }
+  
+chain :: [a -> Maybe a] -> a -> Maybe a
+chain [] x = return x
+chain (f:fs) x = (f x) >>= chain fs 
+  
+chainJust :: [a -> Maybe a] -> a -> a
+chainJust fs x = case chain fs x of
+  Nothing -> error "chainJust: Nothing"
+  Just y  -> y
+  
+--------------------------------------------------------------------------------  
+
+iterateN :: Int -> (a -> a) -> a -> a
+iterateN n f = go n where 
+  go 0 x = x
+  go n x = go (n-1) (f x)
+
+--------------------------------------------------------------------------------  
+ Data/Generics/Fixplate/Morphisms.hs view
@@ -0,0 +1,49 @@+
+-- | Scary named folds...
+
+{-# LANGUAGE CPP #-}
+module Data.Generics.Fixplate.Morphisms where
+
+--------------------------------------------------------------------------------
+
+import Data.Foldable
+import Data.Generics.Fixplate.Base
+
+#ifdef WITH_QUICKCHECK
+import Test.QuickCheck
+import Data.Generics.Fixplate.Traversals
+import Data.Generics.Fixplate.Test.Tools
+#endif 
+
+--------------------------------------------------------------------------------
+
+-- | A /paramorphism/ is a generalized (right) fold.
+para :: Functor f => (Mu f -> f a -> a) -> Mu f -> a
+para h = go where
+  go t = h t (fmap go $ unFix t) 
+
+para' :: Functor f => (f (Mu f, a) -> a) -> Mu f -> a
+para' h = go where
+  go (Fix t) = h (fmap go' $ t)
+  go' t = (t, go t) 
+
+paraList :: (Functor f, Foldable f) => (Mu f -> [a] -> a) -> Mu f -> a 
+paraList f = go where
+  go t = f t (toList $ fmap go $ unFix t)
+
+-- | A /catamorphism/ is a simpler version of a paramorphism
+cata :: Functor f => (f a -> a) -> Mu f -> a
+cata h = go where
+  go = h . fmap go . unFix
+
+-- | An /anamorphism/ is simply an unfold.
+ana :: Functor f => (a -> f a) -> a -> Mu f
+ana h = go where
+  go x = Fix (fmap go (h x))
+
+-- | A /hylomorphism/ is the composition of a catamorphism and an anamorphism.
+hylo :: Functor f => (f a -> a) -> (b -> f b) -> (b -> a) 
+hylo g h = cata g . ana h
+
+--------------------------------------------------------------------------------
+
+ Data/Generics/Fixplate/Structure.hs view
@@ -0,0 +1,47 @@+
+{-# LANGUAGE CPP #-}
+#ifdef __GLASGOW_HASKELL__
+{-# LANGUAGE Rank2Types #-}
+#endif
+
+-- | Changing the structure of a tree.
+module Data.Generics.Fixplate.Structure 
+  ( NatTrafo
+  , restructure
+  , liftAnn
+  )
+  where
+--------------------------------------------------------------------------------
+
+import Data.Generics.Fixplate.Base
+
+--------------------------------------------------------------------------------
+
+#ifdef __GLASGOW_HASKELL__
+
+-- | The type of natural transformations.
+type NatTrafo f g = forall a. (f a -> g a)
+
+-- | Changing the structure of a tree.
+restructure :: Functor f => NatTrafo f g -> Mu f -> Mu g
+restructure trafo = go where
+  go = Fix . trafo . fmap go . unFix
+
+#else  
+
+data NatTrafo f g = NatTrafo (f Int) (g Int)   -- fake and opaque data type
+
+-- | Unfortunately, this function requires Rank2Types,
+-- thus we only provide it for GHC.
+restructure :: Functor f => NatTrafo f g -> Mu f -> Mu g
+restructure = error "restructure: this operation requires Rank2Types"
+
+#endif
+  
+--------------------------------------------------------------------------------
+
+-- | Lifting natural transformations to annotations.
+liftAnn :: (f e -> g e) -> Ann f a e -> Ann g a e
+liftAnn trafo (Ann a x) = Ann a (trafo x)
+
+--------------------------------------------------------------------------------
+ Data/Generics/Fixplate/Test/Instances.hs view
@@ -0,0 +1,129 @@+
+
+{-# LANGUAGE 
+      CPP, 
+      DeriveFunctor, DeriveFoldable, DeriveTraversable, StandaloneDeriving,
+      FlexibleInstances
+  #-}
+module Data.Generics.Fixplate.Test.Instances where
+
+--------------------------------------------------------------------------------
+
+import Control.Applicative
+import Control.Monad hiding (mapM, mapM_, forM, forM_)
+import Data.List (sort)
+import Data.Foldable
+import Data.Traversable
+import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap)
+
+import Data.Generics.Fixplate.Base
+import Data.Generics.Fixplate.Misc
+import Data.Generics.Fixplate.Test.Tools
+
+import Test.QuickCheck
+
+--------------------------------------------------------------------------------
+-- * Misc
+
+prop_forget :: Attr (TreeF Label) Int -> Bool
+prop_forget tree =
+  fromFixT (forget tree) == fmap fst (fromAttr tree)
+  
+prop_fromToFixT :: FixT Label -> Bool  
+prop_fromToFixT tree =
+  toFixT (fromFixT tree) == tree
+
+prop_toFromFixT :: Tree Label -> Bool  
+prop_toFromFixT tree =
+  fromFixT (toFixT tree) == tree
+
+prop_fromToAttr :: Attr (TreeF Label) Int -> Bool  
+prop_fromToAttr tree =
+  toAttr (fromAttr tree) == tree
+
+prop_toFromAttr :: Tree (Label,Int) -> Bool  
+prop_toFromAttr tree =
+  fromAttr (toAttr tree) == tree
+  
+runtests_InstancesMisc = do
+  quickCheck prop_forget
+  quickCheck prop_fromToFixT 
+  quickCheck prop_toFromFixT
+  quickCheck prop_fromToAttr
+  quickCheck prop_toFromAttr
+  
+--------------------------------------------------------------------------------
+-- * Read/Show.
+
+prop_ReadShowMuLabel   :: Mu (TreeF Label ) -> Bool
+prop_ReadShowMuInt     :: Mu (TreeF Int   ) -> Bool
+prop_ReadShowMuString  :: Mu (TreeF String) -> Bool
+
+prop_ReadShowMuLabel  t = read (show t) == t 
+prop_ReadShowMuInt    t = read (show t) == t 
+prop_ReadShowMuString t = read (show t) == t 
+
+prop_ReadShowAttrLabelInt    :: Attr (TreeF Label ) Int   -> Bool
+prop_ReadShowAttrStringLabel :: Attr (TreeF String) Label -> Bool
+
+prop_ReadShowAttrLabelInt    t = read (show t) == t 
+prop_ReadShowAttrStringLabel t = read (show t) == t 
+
+runtests_ReadShow = do
+  quickCheck prop_ReadShowMuLabel
+  quickCheck prop_ReadShowMuInt
+  quickCheck prop_ReadShowMuString
+  quickCheck prop_ReadShowAttrLabelInt
+  quickCheck prop_ReadShowAttrStringLabel
+  
+--------------------------------------------------------------------------------
+-- * Attrib wrapper.
+
+prop_AttribFMap :: Attr (TreeF Label) Int -> Bool
+prop_AttribFMap tree = 
+  unAttrib (fmap f (Attrib tree)) == toAttr (fmap (id<#>f) (fromAttr tree)) 
+    where f n = show n ++ "_"
+
+--------------------------------------------------------------------------------
+
+prop_AttribFoldr :: Attr (TreeF Label) Int -> Bool
+prop_AttribFoldr tree = 
+  foldr (:) [] (Attrib tree) == map snd (foldr (:) [] (fromAttr tree))
+
+prop_AttribFoldl :: Attr (TreeF Label) Int -> Bool
+prop_AttribFoldl tree = 
+  foldl (flip (:)) [] (Attrib tree) == map snd (foldl (flip (:)) [] (fromAttr tree))
+
+--------------------------------------------------------------------------------
+
+prop_AttribMapAccumL :: Attr (TreeF Label) Integer -> Bool
+prop_AttribMapAccumL tree = 
+  (id<#>unAttrib) (mapAccumL f1 666 (Attrib tree)) == (id<#>toAttr) (mapAccumL f2 666 (fromAttr tree)) where 
+    f1 :: Integer -> Integer -> (Integer,String)
+    f1 old input = (new, show residue) where 
+      new     = old*3 - input
+      residue = old*2 + input*7
+    f2 :: Integer -> (Label,Integer) -> (Integer,(Label,String))
+    f2 old (x,input) = let (new,res) = f1 old input in (new,(x,res))
+
+prop_AttribMapAccumR :: Attr (TreeF Label) Integer -> Bool
+prop_AttribMapAccumR tree = 
+  (id<#>unAttrib) (mapAccumR f1 666 (Attrib tree)) == (id<#>toAttr) (mapAccumR f2 666 (fromAttr tree)) where 
+    f1 :: Integer -> Integer -> (Integer,String)
+    f1 old input = (new, show residue) where 
+      new     = old*3 - input
+      residue = old*2 + input*7
+    f2 :: Integer -> (Label,Integer) -> (Integer,(Label,String))
+    f2 old (x,input) = let (new,res) = f1 old input in (new,(x,res))
+
+-- | We compare GHC-derived Functor, Foldable and Traversable instances (for Tree)
+-- with our implementation (for Attrib).
+runtests_Attrib = do
+  quickCheck prop_AttribFMap
+  quickCheck prop_AttribFoldr
+  quickCheck prop_AttribFoldl
+  quickCheck prop_AttribMapAccumL
+  quickCheck prop_AttribMapAccumR
+  
+--------------------------------------------------------------------------------
+  
+ Data/Generics/Fixplate/Test/Tools.hs view
@@ -0,0 +1,157 @@+
+{-# LANGUAGE CPP, 
+             DeriveFunctor, DeriveFoldable, DeriveTraversable, StandaloneDeriving,
+             FlexibleInstances, TypeSynonymInstances
+  #-}
+module Data.Generics.Fixplate.Test.Tools where
+
+--------------------------------------------------------------------------------
+
+import Control.Applicative
+import Control.Monad hiding (mapM, mapM_, forM, forM_)
+import Data.List (sort)
+import Data.Foldable
+import Data.Traversable
+import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap)
+
+import Text.Show
+import Text.Read
+
+import Data.Generics.Fixplate.Base
+
+#ifdef WITH_QUICKCHECK
+import Test.QuickCheck
+#endif 
+
+--------------------------------------------------------------------------------
+
+maxChildren :: Int
+maxChildren = 7
+
+data Tree label
+  = Tree label [Tree label] 
+  deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
+
+data TreeF label t 
+  = TreeF label [t]
+  deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
+  
+type FixT label = Mu (TreeF label)  
+  
+instance Eq   label => EqF   (TreeF label) where equalF     = (==)
+instance Ord  label => OrdF  (TreeF label) where compareF   = compare
+instance Show label => ShowF (TreeF label) where showsPrecF = showsPrec
+#ifdef __GLASGOW_HASKELL__
+instance Read label => ReadF (TreeF label) where readPrecF  = readPrec
+#else
+instance Read label => ReadF (TreeF label) where readsPrecF = readsPrec
+#endif
+  
+treeF :: l -> [Mu (TreeF l)] -> Mu (TreeF l)
+treeF s = Fix . TreeF s
+
+attrTreeF :: a -> l -> [Attr (TreeF l) a] -> Attr (TreeF l) a
+attrTreeF x s = Fix . Ann x . TreeF s
+
+--------------------------------------------------------------------------------
+-- * random trees
+
+rndTree :: IO (Tree Label)
+rndTree = liftM (!!7) $ sample' arbitrary
+
+rndFixT :: IO (FixT Label)
+rndFixT = liftM (!!7) $ sample' arbitrary
+
+--------------------------------------------------------------------------------
+-- * conversion
+
+toFixT :: Tree l -> Mu (TreeF l)
+toFixT (Tree s ts) = treeF s (map toFixT ts)
+
+fromFixT :: FixT l -> Tree l
+fromFixT (Fix (TreeF s ts)) = Tree s (map fromFixT ts)
+
+fromAttr :: Attr (TreeF l) a -> Tree (l,a)
+fromAttr (Fix (Ann x (TreeF s ts))) = Tree (s,x) (map fromAttr ts)
+
+toAttr :: Tree (l,a) -> Attr (TreeF l) a 
+toAttr (Tree (s,x) ts) = Fix (Ann x (TreeF s (map toAttr ts)))
+
+--------------------------------------------------------------------------------
+-- * arbitrary
+
+pairs :: [a] -> [(a,a)]
+pairs (x:xs@(y:_)) = (x,y):(pairs xs)
+pairs [_]          = []
+pairs []           = error "pairs: empty list"
+
+-- | @genPartition n k@ partitions n elements into k groups randomly,
+-- and gives back the sizes (which can be zero, too)
+genPartition :: Int -> Int -> Gen [Int]
+genPartition n k = do
+  sep <- replicateM (k-1) $ choose (0,n)
+  let ps = pairs (0 : sort sep ++ [n]) 
+  return (map (\(x,y) -> (y-x)) ps)
+
+newtype Label = Label String deriving (Eq,Ord,Show,Read)
+
+unLabel :: Label -> String
+unLabel (Label s) = s
+
+instance Arbitrary Label where
+  arbitrary = do
+    n <- choose (2, 8)
+    liftM Label $ vectorOf n $ oneof [ choose ('a','z') , choose ('A','Z') ]
+  
+instance Arbitrary l => Arbitrary (Tree l) where
+  shrink (Tree s sub) = [ Tree s sub' | sub' <- shrink sub ] 
+  arbitrary = sized mkTree where
+    mkTree n = do
+      s <- arbitrary
+      case n of
+        0 -> return (Tree s [])
+        1 -> mkTree 0 >>= \t -> return (Tree s [t])
+        _ -> do
+          k <- choose (1, min maxChildren n)
+          ls <- genPartition (n-1) k
+          subtrees <- forM ls $ \l -> mkTree l
+          return (Tree s subtrees)
+
+instance Arbitrary l => Arbitrary (Mu (TreeF l)) where
+  shrink (Fix (TreeF s sub)) = [ Fix (TreeF s sub') | sub' <- shrink sub ] 
+  arbitrary = sized mkTree  where
+    mkTree n = do
+      s <- arbitrary
+      case n of
+        0 -> return (treeF s [])
+        1 -> mkTree 0 >>= \t -> return (treeF s [t])
+        _ -> do
+          k <- choose (1, min maxChildren n)
+          ls <- genPartition (n-1) k
+          subtrees <- forM ls $ \l -> mkTree l
+          return (treeF s subtrees)
+
+{-          
+instance (Arbitrary a, Arbitrary x) => Arbitrary (Ann TreeF a x) where
+  shrink (Ann a x) = [ Ann a y | y <- shrink x ]
+  arbitrary = do
+    a <- arbitrary
+    x <- arbitrary
+-}
+
+instance (Arbitrary a, Arbitrary l) => Arbitrary (Attr (TreeF l) a) where
+  shrink (Fix (Ann a (TreeF s sub))) = [ Fix (Ann a (TreeF s sub')) | sub' <- shrink sub ] 
+  arbitrary = sized mkTree  where
+    mkTree n = do
+      s <- arbitrary
+      a <- arbitrary
+      case n of
+        0 -> return (attrTreeF a s [])
+        1 -> mkTree 0 >>= \t -> return (attrTreeF a s [t])
+        _ -> do
+          k <- choose (1, min maxChildren n)
+          ls <- genPartition (n-1) k
+          subtrees <- forM ls $ \l -> mkTree l
+          return (attrTreeF a s subtrees)
+              
+--------------------------------------------------------------------------------
+ Data/Generics/Fixplate/Tests.hs view
@@ -0,0 +1,30 @@+
+-- | Run all the tests
+module Data.Generics.Fixplate.Tests where
+  
+--------------------------------------------------------------------------------
+  
+import Data.Generics.Fixplate.Base
+import Data.Generics.Fixplate.Traversals
+import Data.Generics.Fixplate.Morphisms
+import Data.Generics.Fixplate.Attributes
+import Data.Generics.Fixplate.Zipper
+import Data.Generics.Fixplate.Structure  
+
+import Data.Generics.Fixplate.Test.Tools
+import Data.Generics.Fixplate.Test.Instances
+
+import Test.QuickCheck
+
+--------------------------------------------------------------------------------
+
+run_all_tests :: IO ()
+run_all_tests = do
+  putStrLn "tests for instances..."       ; runtests_InstancesMisc
+  putStrLn "tests for Read/Show..."       ; runtests_ReadShow
+  putStrLn "tests for Attrib wrapper..."  ; runtests_Attrib
+  putStrLn "tests for traversals..."      ; runtests_Traversals
+  putStrLn "tests for Attributes..."      ; runtests_Attributes
+  putStrLn "tests for zippers..."         ; runtests_Zipper
+
+--------------------------------------------------------------------------------
+ Data/Generics/Fixplate/Traversals.hs view
@@ -0,0 +1,156 @@+
+-- | Uniplate-style traversals.
+
+{-# LANGUAGE CPP #-}
+module Data.Generics.Fixplate.Traversals where
+
+--------------------------------------------------------------------------------
+
+import Control.Monad (liftM)
+import Data.Foldable
+import Data.Traversable
+import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap)
+
+import Data.Generics.Fixplate.Base 
+import Data.Generics.Fixplate.Misc
+
+#ifdef WITH_QUICKCHECK
+import Test.QuickCheck
+import Data.Generics.Fixplate.Test.Tools
+#endif
+
+--------------------------------------------------------------------------------
+-- * Queries
+
+-- | The list of direct descendants.
+children :: Foldable f => Mu f -> [Mu f]
+children = foldr (:) [] . unFix
+
+-- | The list of all substructures. Together with list-comprehension syntax
+-- this is a powerful query tool.
+universe :: Foldable f => Mu f -> [Mu f]
+universe x = x : concatMap universe (children x)
+
+--------------------------------------------------------------------------------
+-- * Traversals
+
+-- | Bottom-up transformation.
+transform :: Functor f => (Mu f -> Mu f) -> Mu f -> Mu f 
+transform h = go where 
+  go = h . Fix . fmap go . unFix
+
+transformM  ::  (Traversable f, Monad m) 
+            =>  (Mu f -> m (Mu f)) -> Mu f -> m (Mu f)
+transformM action = go where
+  go (Fix x) = do 
+    y <- mapM go x
+    action (Fix y)
+
+-- | Top-down transformation. This provided only for completeness;
+-- usually, it is 'transform' what you want use instead.
+topDownTransform :: Functor f => (Mu f -> Mu f) -> Mu f -> Mu f 
+topDownTransform h = go where 
+  go = Fix . fmap go . unFix . h
+
+topDownTransformM :: (Traversable f, Monad m) => (Mu f -> m (Mu f)) -> Mu f -> m (Mu f)
+topDownTransformM h = go where 
+  go x = do
+    Fix y <- h x
+    liftM Fix (mapM go y)
+  
+-- | Non-recursive top-down transformation.
+descend :: Functor f => (Mu f -> Mu f) -> Mu f -> Mu f 
+descend h = Fix . fmap h . unFix
+
+descendM :: (Traversable f, Monad m) => (Mu f -> m (Mu f)) -> Mu f -> m (Mu f)
+descendM action = liftM Fix . mapM action . unFix
+
+-- | Bottom-up transformation until a normal form is reached.
+rewrite :: Functor f => (Mu f -> Maybe (Mu f)) -> Mu f -> Mu f 
+rewrite h = transform g  where 
+  g x = maybe x (rewrite h) (h x)
+
+rewriteM :: (Traversable f, Monad m) => (Mu f -> m (Maybe (Mu f))) -> Mu f -> m (Mu f)
+rewriteM h = transformM g where 
+  g x = h x >>= \y -> maybe (return x) (rewriteM h) y
+  
+--------------------------------------------------------------------------------
+-- * Context
+
+-- | We /annotate/ the nodes of the tree with functions which replace that
+-- particular subtree.
+context :: Traversable f => Mu f -> Attr f (Mu f -> Mu f)
+context = go id where
+  go h = Fix . Ann h . fmap g . holes . unFix where
+    g (y,replace) = go (h . Fix . replace) y where 
+
+-- | Flattened version of 'context'.
+contextList :: Traversable f => Mu f -> [(Mu f, Mu f -> Mu f)]
+contextList = map h . universe . context where
+  h this@(Fix (Ann g x)) = (forget this, g)
+
+--------------------------------------------------------------------------------
+-- * Folds
+
+-- | Left fold. Since @Mu f@ is not a functor, but a type, we cannot make
+-- it an instance of the @Foldable@ type class.
+foldLeft :: Foldable f => (a -> Mu f -> a) -> a -> Mu f -> a
+foldLeft h x0 t = go x0 t where
+  go x t = foldl go (h x t) $ unFix t
+
+foldRight :: Foldable f => (Mu f -> a -> a) -> a -> Mu f -> a
+foldRight h x0 t = go t x0 where
+  go t x = h t $ foldr go x $ unFix t 
+
+--------------------------------------------------------------------------------
+-- * Open functions
+
+-- | The children together with functions replacing that particular child.    
+holes :: Traversable f => f a -> f (a, a -> f a)
+holes tree = mapAccumL_ ithHole 1 tree where
+  ithHole i x = (i+1, (x,h)) where          
+    h y = mapAccumL_ g 1 tree where         
+      g j z = (j+1, if i==j then y else z)  
+
+holesList :: Traversable f => f a -> [(a, a -> f a)]
+holesList = toList . holes
+
+-- | Apply the given function to each child in turn.
+apply :: Traversable f => (a -> a) -> f a -> f (f a)
+apply f tree = fmap g (holes tree) where
+  g (x,replace) = replace (f x)
+
+-- | Builds up a structure from a list of the children.
+builder :: Traversable f => f a -> [b] -> f b
+builder tree xs = mapAccumL_ g xs tree where
+  g (x:xs) _ = (xs,x)
+
+--------------------------------------------------------------------------------
+#ifdef WITH_QUICKCHECK
+-- * Tests
+
+universeNaive :: Foldable f => Mu f -> [Mu f]
+universeNaive x = x : concatMap universeNaive (children x)
+
+runtests_Traversals = do
+  quickCheck prop_leftFold
+  quickCheck prop_rightFold
+  quickCheck prop_universe1
+  quickCheck prop_universe2
+  
+prop_universe1 :: FixT Label -> Bool
+prop_universe1 tree = universe tree == universeNaive tree
+
+prop_universe2 :: FixT Label -> Bool
+prop_universe2 tree = universe tree == foldRight (:) [] tree
+  
+prop_leftFold :: FixT Label -> Bool
+prop_leftFold tree = 
+  foldLeft (\xs (Fix (TreeF l s)) -> (l:xs)) [] tree == foldl (flip (:)) [] (fromFixT tree)
+
+prop_rightFold :: FixT Label -> Bool
+prop_rightFold tree = 
+  foldRight (\(Fix (TreeF l s)) xs -> (l:xs)) [] tree == foldr (:) [] (fromFixT tree)
+
+#endif
+--------------------------------------------------------------------------------
+ Data/Generics/Fixplate/Zipper.hs view
@@ -0,0 +1,460 @@+
+{-# LANGUAGE CPP #-}
+#ifdef WITH_QUICKCHECK
+{-# LANGUAGE TypeSynonymInstances #-}
+#endif
+
+-- | The Zipper.
+module Data.Generics.Fixplate.Zipper where
+
+--------------------------------------------------------------------------------
+
+import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap)
+import Data.Foldable
+import Data.Traversable
+import Data.Maybe
+
+import Text.Show
+import Text.Read 
+
+import Data.Generics.Fixplate.Base
+import Data.Generics.Fixplate.Misc
+
+#ifdef WITH_QUICKCHECK
+import Test.QuickCheck
+import Data.Generics.Fixplate.Traversals
+import Data.Generics.Fixplate.Attributes
+import Data.Generics.Fixplate.Test.Tools
+import Control.Monad (liftM)
+#endif 
+
+--------------------------------------------------------------------------------
+-- * Types
+
+type Node f  =  Either (Mu f) (Path f)
+
+data Path f  =  Top
+             |  Path { unPath :: f (Node f) } 
+               
+data Loc f   =  Loc { focus :: Mu f , path :: Path f } 
+
+--------------------------------------------------------------------------------
+
+instance EqF f => Eq (Path f) where               
+  Top     == Top      = True
+  Path p1 == Path p2  = equalF p1 p2
+  _       == _        = False
+  
+instance EqF f => Eq (Loc f) where               
+  Loc f1 p1 == Loc f2 p2  = f1 == f2 && p1 == p2
+  
+instance ShowF f => Show (Path f) where               
+  showsPrec d Top = showString "Top"
+  showsPrec d (Path xs) = showParen (d>10) 
+    $ showString "Path "
+    . showsPrecF 11 xs
+
+instance ShowF f => Show (Loc f) where
+  showsPrec d (Loc foc path) = showParen (d>10) 
+    $ showString "Loc "
+    . showsPrec 11 foc
+    . showChar ' '
+    . showsPrec 11 path
+
+instance ReadF f => Read (Path f) where 
+#ifdef __GLASGOW_HASKELL__
+  readPrec = parens $ 
+    (do
+      { Ident "Top" <- lexP
+      ; return Top            
+      })
+    +++
+    (prec app_prec $ do
+      { Ident "Path" <- lexP
+      ; p <- step readPrecF
+      ; return (Path p)            
+      })    
+#else                                  
+  readsPrec d r = readParen (d > app_prec)
+     (\r -> [ (Top, s) 
+            | ("Top", s) <- lex r]) r    
+     ++
+     (\r -> [ (Path p, t) 
+            | ("Path", s) <- lex r
+            , (f,t) <- readsPrecF (app_prec+1) s]) r    
+            
+#endif
+    
+instance ReadF f => Read (Loc f) where 
+#ifdef __GLASGOW_HASKELL__
+  readPrec = parens $ 
+    (prec app_prec $ do
+      { Ident "Loc" <- lexP
+      ; f <- step readPrec
+      ; p <- step readPrec
+      ; return (Loc f p)            
+      })
+#else                                  
+  readsPrec d r = readParen (d > app_prec)
+     (\r -> [ (Loc f p, u) 
+            | ("Loc", s) <- lex r
+            , (f,t) <- readsPrec (app_prec+1) s
+            , (p,u) <- readsPrec (app_prec+1) t]) r    
+#endif
+
+--------------------------------------------------------------------------------
+-- * Converting to and from zippers
+
+-- | Creates a zipper from a tree, with the focus at the root.
+root :: Mu f -> Loc f
+root t = Loc t Top
+
+-- | Restores a tree from a zipper.
+defocus :: Traversable f => Loc f -> Mu f
+defocus (Loc foc path) = go foc path where
+  go t Top = t
+  go t (Path xs)  = go (Fix s) path' where
+    (Just path', s) = mapAccumL h Nothing xs
+    h  old  (Left   y)  =  (old     , y)
+    h  _    (Right  p)  =  (Just p  , t)
+
+-- | The zipper version of 'forget'.
+locForget :: Functor f => Loc (Ann f a) -> Loc f    
+locForget (Loc foc path) = Loc (forget foc) (go path) where
+  go :: Functor f => Path (Ann f a) -> Path f    
+  go Top = Top
+  go (Path (Ann _ nodes)) = Path (fmap h nodes)
+  
+  h :: Functor f => Node (Ann f a) -> Node f    
+  h (Left  t) = Left  (forget t)
+  h (Right p) = Right (go p)
+    
+--------------------------------------------------------------------------------
+-- * Manipulating the subtree at focus
+
+extract :: Loc f -> Mu f
+extract = focus
+
+replace :: Mu f -> Loc f -> Loc f
+replace new loc = loc { focus = new }
+
+modify :: (Mu f -> Mu f) -> Loc f -> Loc f
+modify h loc = replace (h (focus loc)) loc
+
+--------------------------------------------------------------------------------
+-- * Safe movements
+
+-- | Moves down the child with the given index.
+-- The leftmost children has index @0@.
+moveDown :: Traversable f => Int -> Loc f -> Maybe (Loc f)
+moveDown pos (Loc foc path) = new where
+  new = case mfoc' of  
+     Nothing    ->  Nothing
+     Just foc'  ->  Just $ Loc foc' (Path nodes')
+  ((mfoc',_),nodes')  =  mapAccumL g (Nothing,0) (unFix foc)    
+  g (old,j) x  =  if j==pos 
+    then  ((Just x  , j+1),  Right  path  ) 
+    else  ((old     , j+1),  Left   x     )      
+
+-- | Moves down the leftmost child.
+moveDownL :: Traversable f => Loc f -> Maybe (Loc f)
+moveDownL (Loc foc path) = new where
+  new = case mfoc' of  
+     Nothing    ->  Nothing
+     Just foc'  ->  Just $ Loc foc' (Path nodes')
+  (mfoc',nodes')  =  mapAccumL g Nothing (unFix foc)    
+  g old x  = case old of
+    Nothing  -> (Just x  ,  Right  path  ) 
+    _        -> (old     ,  Left   x     )      
+
+-- | Moves down the rightmost child.
+moveDownR :: Traversable f => Loc f -> Maybe (Loc f)
+moveDownR (Loc foc path) = new where
+  new = case mfoc' of  
+     Nothing    ->  Nothing
+     Just foc'  ->  Just $ Loc foc' (Path nodes')
+  (mfoc',nodes')  =  mapAccumR g Nothing (unFix foc)    
+  g old x  = case old of
+    Nothing  -> (Just x  ,  Right  path  ) 
+    _        -> (old     ,  Left   x     )      
+    
+--------------------------------------------------------------------------------
+
+moveUp :: Traversable f => Loc f -> Maybe (Loc f)
+moveUp (Loc foc path) = case path of
+  Top         -> Nothing
+  Path nodes  -> 
+    case mpath of
+      Nothing      -> error "moveUp: shouldn't happen"
+      Just path'   -> Just $ case path' of
+        Path nodes'    -> Loc (Fix foc') (Path nodes')
+        Top            -> Loc (Fix foc') Top
+    where      
+      (mpath,foc') = mapAccumL g Nothing nodes 
+      g old ei = case ei of
+        Right  p  -> (Just p  , foc)
+        Left   x  -> (old     , x  )
+
+--------------------------------------------------------------------------------
+
+moveRight :: Traversable f => Loc f -> Maybe (Loc f)
+moveRight (Loc foc path) = case path of
+  Top         -> Nothing
+  Path nodes  -> 
+    case two of
+      Two foc' -> Just $ Loc foc' (Path nodes')
+      _        -> Nothing
+    where      
+      (two,nodes') = mapAccumL g Empty nodes 
+      g old ei = case ei of
+        Right  p  ->  (One p  , Left foc  )
+        Left   x  -> case old of
+          One p ->    (Two x  , Right p   )
+          _     ->    (old    , ei        )
+
+moveLeft :: Traversable f => Loc f -> Maybe (Loc f)
+moveLeft (Loc foc path) = case path of
+  Top         -> Nothing
+  Path nodes  -> 
+    case two of
+      Two foc' -> Just $ Loc foc' (Path nodes')
+      _        -> Nothing
+    where      
+      (two,nodes') = mapAccumR g Empty nodes 
+      g old ei = case ei of
+        Right  p  ->  (One p  , Left foc  )
+        Left   x  -> case old of
+          One p ->    (Two x  , Right p   )
+          _     ->    (old    , ei        )
+
+--------------------------------------------------------------------------------
+-- * Testing for borders
+
+-- | Checks whether we are the top.
+isTop :: Loc f -> Bool
+isTop (Loc _ p) = case p of { Top -> True ; _ -> False }
+
+-- | Checks whether we cannot move down.
+isBottom :: Traversable f => Loc f -> Bool
+isBottom = isNothing . moveDownL
+
+isLeftmost :: Traversable f => Loc f -> Bool
+isLeftmost = isNothing . moveLeft
+
+isRightmost :: Traversable f => Loc f -> Bool
+isRightmost = isNothing . moveRight
+
+--------------------------------------------------------------------------------
+-- * Compound movements
+  
+-- | Moves to the top, by repeatedly moving up.
+moveTop :: Traversable f => Loc f -> Loc f
+moveTop = tillNothing moveUp
+
+-- | Moves left until it can.
+leftmost :: Traversable f => Loc f -> Loc f
+leftmost = tillNothing moveLeft
+
+-- | Moves right until it can.
+rightmost :: Traversable f => Loc f -> Loc f
+rightmost = tillNothing moveRight
+
+--------------------------------------------------------------------------------
+-- * Unsafe movements
+
+unsafeMoveDown :: Traversable f => Int -> Loc f -> Loc f
+unsafeMoveDown i = unsafe (moveDown i) "unsafeMoveDown: cannot move down"
+  
+unsafeMoveDownL :: Traversable f => Loc f -> Loc f
+unsafeMoveDownR :: Traversable f => Loc f -> Loc f
+unsafeMoveUp    :: Traversable f => Loc f -> Loc f
+
+unsafeMoveDownL = unsafe moveDownL "unsafeMoveDownL: cannot move down"
+unsafeMoveDownR = unsafe moveDownR "unsafeMoveDownR: cannot move down"  
+unsafeMoveUp    = unsafe moveUp    "unsafeMoveUp: cannot move up"  
+
+unsafeMoveLeft, unsafeMoveRight :: Traversable f => Loc f -> Loc f
+unsafeMoveLeft  = unsafe moveLeft  "unsafeMoveLeft: cannot move left"  
+unsafeMoveRight = unsafe moveRight "unsafeMoveRight: cannot move right"    
+
+--------------------------------------------------------------------------------
+#ifdef WITH_QUICKCHECK
+-- * Tests
+
+type LocT a = Loc (TreeF a)
+
+data Step
+  = StepUp
+  | StepLeft
+  | StepRight
+  | StepDown Int
+  | StepDownL
+  | StepDownR
+  deriving (Eq,Ord,Show)
+
+newtype Walk = Walk [Step] deriving (Eq,Ord,Show)
+  
+walk :: Traversable f => Walk -> Loc f -> Loc f  
+walk (Walk steps) loc = foldl (flip singleStep) loc steps
+
+singleStep :: Traversable f => Step -> Loc f -> Loc f
+singleStep s loc = case stepMaybe s loc of { Nothing -> loc ; Just new -> new }
+
+stepMaybe :: Traversable f => Step -> Loc f -> Maybe (Loc f)
+stepMaybe s = case s of
+  StepUp     -> moveUp
+  StepLeft   -> moveLeft
+  StepRight  -> moveRight
+  StepDown j -> moveDown j
+  StepDownL  -> moveLeft
+  StepDownR  -> moveRight
+  
+instance Arbitrary Step where
+  arbitrary = oneof
+    [ return StepUp
+    , return StepLeft
+    , return StepRight
+    , do { j <- choose (1,7) ; return (StepDown j) }
+    , return StepDownL
+    , return StepDownR
+    ]
+
+instance Arbitrary Walk where
+  arbitrary = liftM Walk arbitrary
+  shrink (Walk steps) = map Walk (shrink steps)
+
+-- | Assuming a left-to-right canonical numbering, we find the given
+-- location.
+findLoc :: Traversable f => Int -> Loc (Ann f Int) -> Loc (Ann f Int) 
+findLoc k = go where
+  go loc = 
+    case compare j k of
+      GT -> error "findLoc: shouldn't happen?"
+      EQ -> loc
+      LT -> case moveDownL loc of
+        Just xx -> go xx
+        Nothing -> case moveRight loc of
+          Just yy -> go yy
+          Nothing -> goUpR (unsafeMoveUp loc)
+    where
+      Fix (Ann j _) = focus loc
+  goUpR loc = case moveRight loc of
+    Nothing -> goUpR (unsafeMoveUp loc)
+    Just zz -> go zz
+
+--
+tmp = treeF "root"
+  [ treeF "a" [ treeF "a1" [] , treeF "a2" [] ]
+  , treeF "b" []
+  , treeF "c" [ treeF "c1" [] , treeF "c2" [] , treeF "c3" [] ]
+  ]
+--
+  
+instance Arbitrary a => Arbitrary (LocT a) where
+  arbitrary = do
+    tree <- arbitrary 
+    let (n,numbered) = numberNodes tree
+    k <- choose (0,n-1)
+    return $ locForget $ findLoc k (root numbered)
+
+rndLoc :: IO (LocT Label)
+rndLoc = liftM (!!7) $ sample' arbitrary
+  
+newtype ChildIndex = ChildIndex Int deriving Show
+
+instance Arbitrary ChildIndex where
+  arbitrary = liftM ChildIndex $ choose (0,7)
+  
+--------------------------------------------------------------------------------
+
+runtests_Zipper = do
+  quickCheck prop_ReadShowLoc
+  quickCheck prop_findLoc
+  quickCheck prop_contextList
+  quickCheck prop_Top
+  quickCheck prop_DownLUp
+  quickCheck prop_DownRUp
+  quickCheck prop_UpDownL 
+  quickCheck prop_UpDownR
+  quickCheck prop_DownL
+  quickCheck prop_DownR
+  quickCheck prop_UpDownJ
+  quickCheck prop_LeftRight
+  quickCheck prop_RightLeft
+
+----------------------------------------
+
+prop_ReadShowLoc :: LocT Label -> Bool
+prop_ReadShowLoc loc = read (show loc) == loc
+
+prop_findLoc :: FixT Label -> Bool
+prop_findLoc tree = [0..n-1] == [ attribute $ focus $ findLoc i top | i<-[0..n-1] ] where
+  top = root numbered
+  (n,numbered) = numberNodes tree
+
+prop_contextList :: FixT Label -> Bool  
+prop_contextList tree =
+  map (\(Fix (TreeF l ts),replace) -> replace (Fix (TreeF (h l) ts))) (contextList tree)
+  ==
+  [ defocus $ modify (\(Fix (TreeF l ts)) -> Fix (TreeF (h l) ts) ) $ locForget $ findLoc i top | i<-[0..n-1] ]
+  where
+    top = root numbered
+    (n,numbered) = numberNodes tree
+    h (Label xs) = Label ('_':xs)
+  
+prop_Top :: LocT Label -> Bool
+prop_Top loc = root (defocus loc) == moveTop loc
+
+----------------------------------------
+    
+prop_DownLUp :: LocT Label -> Property
+prop_DownLUp loc = 
+  (not $ isBottom loc) 
+  ==> unsafeMoveUp (unsafeMoveDownL loc) == loc
+
+prop_DownRUp :: LocT Label -> Property  
+prop_DownRUp loc = 
+  (not $ isBottom loc) 
+  ==> unsafeMoveUp (unsafeMoveDownR loc) == loc
+
+prop_UpDownL :: LocT Label -> Property
+prop_UpDownL loc = 
+  (not $ isTop loc) 
+  ==> unsafeMoveDownL (unsafeMoveUp loc) == leftmost loc
+
+prop_UpDownR :: LocT Label -> Property
+prop_UpDownR loc = 
+  (not $ isTop loc) 
+  ==> unsafeMoveDownR (unsafeMoveUp loc) == rightmost loc
+
+prop_DownL :: LocT Label -> Property
+prop_DownL loc =
+  (not $ isBottom loc)
+  ==> unsafeMoveDownL loc == unsafeMoveDown 0 loc
+
+prop_DownR :: LocT Label -> Property
+prop_DownR loc =
+  (not $ isBottom loc)
+  ==> let k = length $ children $ focus loc
+      in  unsafeMoveDownR loc == unsafeMoveDown (k-1) loc
+
+prop_UpDownJ :: ChildIndex -> LocT Label -> Property
+prop_UpDownJ (ChildIndex j) loc = 
+  (not $ isTop loc) 
+  ==> (j < (length $ children $ focus $ unsafeMoveUp loc))  
+  ==> unsafeMoveDown j (unsafeMoveUp loc) == iterateN j unsafeMoveRight (leftmost loc)
+
+prop_LeftRight :: LocT Label -> Property
+prop_LeftRight loc = 
+  (not $ isLeftmost loc)
+  ==> unsafeMoveRight (unsafeMoveLeft loc) == loc  
+
+prop_RightLeft :: LocT Label -> Property
+prop_RightLeft loc = 
+  (not $ isRightmost loc)
+  ==> (unsafeMoveLeft (unsafeMoveRight loc) == loc)  
+
+--------------------------------------------------------------------------------
+
+#endif 
+
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2011, Balazs Komuves+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither names of the copyright holders nor the names of the contributors+may be used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Setup.lhs view
@@ -0,0 +1,3 @@+#! /usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ fixplate.cabal view
@@ -0,0 +1,61 @@+
+Name:                fixplate
+Version:             0.1
+Synopsis:            Uniplate-style generic traversals for fixed-point types, with some extras.
+Description:         Uniplate-style generic traversals for fixed-point types, which can be  
+                     optionally annotated with attributes. We also provide a generic zipper.
+                     See the module "Data.Generics.Fixplate" and then the individual modules
+                     for more detailed information.
+License:             BSD3
+License-file:        LICENSE
+Author:              Balazs Komuves
+Copyright:           (c) 2011 Balazs Komuves
+Maintainer:          bkomuves (plus) hackage (at) gmail (dot) com
+Homepage:            http://code.haskell.org/~bkomuves/
+Stability:           Experimental
+Category:            Generics
+Tested-With:         GHC == 7.0.3
+Cabal-Version:       >= 1.2
+Build-Type:          Simple
+
+Flag withQuickCheck
+  Description: Compile with the QuickCheck tests. 
+  default: False
+
+Flag base4
+  Description: Base v4
+  
+Library
+  if flag(base4)
+    Build-Depends:       base >= 4 && < 5
+    cpp-options:         -DBASE_VERSION=4
+  else 
+    Build-Depends:       base >= 3 && < 4
+    cpp-options:         -DBASE_VERSION=3
+
+  if flag(withQuickCheck)
+    Build-Depends:       QuickCheck > 2.4
+    cpp-options:         -DWITH_QUICKCHECK
+
+  Exposed-Modules:     Data.Generics.Fixplate
+                       Data.Generics.Fixplate.Base
+                       Data.Generics.Fixplate.Traversals
+                       Data.Generics.Fixplate.Morphisms
+                       Data.Generics.Fixplate.Attributes
+                       Data.Generics.Fixplate.Zipper
+                       Data.Generics.Fixplate.Structure
+ 
+  Other-Modules:       Data.Generics.Fixplate.Misc
+
+  if flag(withQuickCheck)  
+    Exposed-Modules:     Data.Generics.Fixplate.Test.Tools
+                         Data.Generics.Fixplate.Test.Instances
+                         Data.Generics.Fixplate.Tests
+ 
+  Extensions:          CPP
+
+  Hs-Source-Dirs:      .
+
+  ghc-options:         -Wall -fno-warn-unused-matches
+
+