packages feed

fixplate 0.1.2 → 0.1.3

raw patch · 11 files changed

+398/−24 lines, 11 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Generics.Fixplate.Attributes: mapAccumCata :: Functor f => (f acc -> b -> (acc, c)) -> Attr f b -> (acc, Attr f c)
+ Data.Generics.Fixplate.Attributes: scanCata :: Functor f => (a -> f b -> b) -> Attr f a -> Attr f b
+ Data.Generics.Fixplate.Attributes: scanPara :: Functor f => (Attr f a -> f b -> b) -> Attr f a -> Attr f b
+ Data.Generics.Fixplate.Attributes: synthAccumCata :: Functor f => (f acc -> (acc, b)) -> Mu f -> (acc, Attr f b)
+ Data.Generics.Fixplate.Attributes: synthAccumPara :: Functor f => (Mu f -> f acc -> (acc, b)) -> Mu f -> (acc, Attr f b)
+ Data.Generics.Fixplate.Attributes: synthCata :: Functor f => (f a -> a) -> Mu f -> Attr f a
+ Data.Generics.Fixplate.Attributes: synthCataM :: (Traversable f, Monad m) => (f a -> m a) -> Mu f -> m (Attr f a)
+ Data.Generics.Fixplate.Attributes: synthPara :: Functor f => (Mu f -> f a -> a) -> Mu f -> Attr f a
+ Data.Generics.Fixplate.Attributes: synthPara' :: Functor f => (f (Mu f, a) -> a) -> Mu f -> Attr f a
+ Data.Generics.Fixplate.Attributes: synthParaM :: (Traversable f, Monad m) => (Mu f -> f a -> m a) -> Mu f -> m (Attr f a)
+ Data.Generics.Fixplate.Attributes: synthParaM' :: (Traversable f, Monad m) => (f (Mu f, a) -> m a) -> Mu f -> m (Attr f a)
+ Data.Generics.Fixplate.Attributes: synthZygo :: Functor f => (f b -> b) -> (f (b, a) -> a) -> Mu f -> Attr f (b, a)
+ Data.Generics.Fixplate.Attributes: synthZygoWith :: Functor f => (b -> a -> c) -> (f b -> b) -> (f (b, a) -> a) -> Mu f -> Attr f c
+ Data.Generics.Fixplate.Attributes: synthZygo_ :: Functor f => (f b -> b) -> (f (b, a) -> a) -> Mu f -> Attr f a
+ Data.Generics.Fixplate.Morphisms: CoFree :: (a, f (CoFree f a)) -> CoFree f a
+ Data.Generics.Fixplate.Morphisms: Free :: Either a (f (Free f a)) -> Free f a
+ Data.Generics.Fixplate.Morphisms: apo :: Functor f => (a -> f (Either (Mu f) a)) -> a -> Mu f
+ Data.Generics.Fixplate.Morphisms: cataM :: (Monad m, Traversable f) => (f a -> m a) -> Mu f -> m a
+ Data.Generics.Fixplate.Morphisms: cataM_ :: (Monad m, Traversable f) => (f a -> m a) -> Mu f -> m ()
+ Data.Generics.Fixplate.Morphisms: futu :: Functor f => (a -> f (Free f a)) -> a -> Mu f
+ Data.Generics.Fixplate.Morphisms: histo :: Functor f => (f (CoFree f a) -> a) -> Mu f -> a
+ Data.Generics.Fixplate.Morphisms: newtype CoFree f a
+ Data.Generics.Fixplate.Morphisms: newtype Free f a
+ Data.Generics.Fixplate.Morphisms: paraM :: (Monad m, Traversable f) => (Mu f -> f a -> m a) -> Mu f -> m a
+ Data.Generics.Fixplate.Morphisms: paraM_ :: (Monad m, Traversable f) => (Mu f -> f a -> m a) -> Mu f -> m ()
+ Data.Generics.Fixplate.Morphisms: unCoFree :: CoFree f a -> (a, f (CoFree f a))
+ Data.Generics.Fixplate.Morphisms: unFree :: Free f a -> Either a (f (Free f a))
+ Data.Generics.Fixplate.Morphisms: zygo :: Functor f => (f b -> b) -> (f (b, a) -> a) -> Mu f -> (b, a)
+ Data.Generics.Fixplate.Morphisms: zygo_ :: Functor f => (f b -> b) -> (f (b, a) -> a) -> Mu f -> a

Files

Data/Generics/Fixplate.hs view
@@ -49,6 +49,10 @@ -- the @Rank2Types@ extension. For compatibility, the functionality
 -- of this module is at the moment only provided when compiled with GHC or Hugs.
 --
+-- Note: to obtain 'Eq', 'Ord', 'Show', 'Read' and other instances for 
+-- fixed point types like @Mu Expr1@, consult the documentation of the
+-- 'EqF' type class (cf. the related 'OrdF', 'ShowF' and 'ReadF' classes)
+--
 module Data.Generics.Fixplate 
   ( module Data.Generics.Fixplate.Base
   , module Data.Generics.Fixplate.Traversals
Data/Generics/Fixplate/Attributes.hs view
@@ -6,7 +6,16 @@   ( Attrib(..)
   , annMap
   -- * Synthetised attributes
-  , synthetise , synthetise' , synthetiseList , synthetiseM
+  , synthetise  
+  , synthetise' , synthetiseList
+  , synthetiseM
+  -- * Synthetised attributes as generalized cata- and paramorphisms
+  , synthCata   , scanCata
+  , synthPara   , synthPara' , scanPara
+  , synthZygo_  , synthZygo  , synthZygoWith
+  , synthAccumCata , synthAccumPara 
+  , mapAccumCata
+  , synthCataM  , synthParaM  , synthParaM'
   -- * Inherited attributes
   , inherit , inherit'
   , inheritM , inheritM_
@@ -25,9 +34,20 @@ #ifdef WITH_QUICKCHECK
   -- * Tests
   , runtests_Attributes  
+  , scanCataNaive , mapAccumCataNaive
   , prop_synthAccumL
   , prop_synthAccumR
   , prop_synthetise
+  , prop_synthCata
+  , prop_synthPara
+  , prop_synthPara'
+  , prop_scanCata 
+  , prop_mapAccumCata
+  -- * Morphism tests which are here to avoid circular imports
+  , zygoNaive_
+  , zygoNaive
+  , prop_zygo
+  , prop_zygo_
 #endif  
   )
   where
@@ -44,6 +64,11 @@ 
 #ifdef WITH_QUICKCHECK
 import Test.QuickCheck
+import Data.List (intercalate)
+import Data.Char (ord)
+import qualified Prelude
+import Data.Generics.Fixplate.Misc
+import Data.Generics.Fixplate.Morphisms
 import Data.Generics.Fixplate.Traversals
 import Data.Generics.Fixplate.Test.Tools
 #endif 
@@ -68,30 +93,152 @@ --
 -- (note that @sum@ here is @Data.Foldable.sum == Prelude.sum . Data.Foldable.toList@)
 --
+-- See also 'synthCata'.
 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
+synthetise = synthCata
  
--- | Generalization of @scanr@ for trees.
+-- | Generalization of @scanr@ for trees. See also 'scanCata'.
 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
 
+-- | List version of 'synthetise' (compare with Uniplate)
 synthetiseList :: (Functor f, Foldable f) => ([a] -> a) -> Mu f -> Attr f a
 synthetiseList h = synthetise (h . toList)
 
 -- | Monadic version of 'synthetise'.
 synthetiseM  ::  (Traversable f, Monad m) =>  (f a -> m a) -> Mu f -> m (Attr f a)
-synthetiseM act = go where
+synthetiseM = synthCataM 
+
+--------------------------------------------------------------------------------
+-- Synthetised attributes as generalized cata- and paramorphisms
+
+-- | Synonym for 'synthetise', motivated by the equation
+--
+-- >  attribute . synthCata f == cata f
+--
+-- That is, it attributes all subtrees with the result of the corresponding catamorphism.
+synthCata :: Functor f => (f a -> a) -> Mu f -> Attr f a
+synthCata h = go where
+  go (Fix x) = Fix $ Ann (h a) y where 
+    y  =  fmap go x  
+    a  =  fmap attribute y
+
+-- | Synonym for 'synthetise''. Note that this could be a special case of 'synthCata':
+--
+-- > scanCata f == annZipWith (flip const) . synthCata (\(Ann a x) -> f a x)
+--
+-- Catamorphim ('cata') is the generalization of @foldr@ from lists to trees; 
+-- 'synthCata' is one generalization of @scanr@, and 'scanCata' is another generalization.
+scanCata :: Functor f => (a -> f b -> b) -> Attr f a -> Attr f b
+scanCata h =  go where
+  go (Fix (Ann a x)) = Fix $ Ann (h a b) y where 
+    y  =  fmap go x  
+    b  =  fmap attribute y
+
+-- | Attributes all subtrees with the result of the corresponding paramorphism.
+--
+-- >  attribute . synthPara f == para f
+--
+synthPara :: Functor f => (Mu f -> f a -> a) -> Mu f -> Attr f a
+synthPara h = go where
+  go t@(Fix x) = Fix $ Ann (h t a) y where 
+    y  =  fmap go x  
+    a  =  fmap attribute y
+
+-- | Another version of 'synthPara'. This satisfies
+--
+-- >  attribute . synthPara' f == para' f
+--
+synthPara' :: Functor f => (f (Mu f, a) -> a) -> Mu f -> Attr f a
+synthPara' h = snd . go where
+  go orig@(Fix x) = ( orig , Fix $ Ann (h lft) rht ) where 
+    lft = fmap (\(s,t) -> (s, attribute t)) uv
+    rht = fmap snd uv    -- :: f (Attr f a)
+    uv  = fmap go x      -- :: f (Mu f , Attr f a)
+
+scanPara :: Functor f => (Attr f a -> f b -> b) -> Attr f a -> Attr f b
+scanPara h = go where
+  go t@(Fix (Ann a x)) = Fix $ Ann (h t b) y where 
+    y  =  fmap go x  
+    b  =  fmap attribute y
+
+-- | Synthetising zygomorphism. 
+-- 
+-- > attribute . synthZygo_ g h == zygo_ g h
+synthZygo_ :: Functor f => (f b -> b) -> (f (b,a) -> a) -> Mu f -> Attr f a
+synthZygo_ = synthZygoWith (flip const)
+
+synthZygo :: Functor f => (f b -> b) -> (f (b,a) -> a) -> Mu f -> Attr f (b,a)
+synthZygo = synthZygoWith (,)
+
+synthZygoWith :: Functor f => (b -> a -> c) -> (f b -> b) -> (f (b,a) -> a) -> Mu f -> Attr f c
+synthZygoWith u g h = snd . go where
+  go (Fix t) = ( (b,a) , Fix (Ann (u b a) s) ) where
+    b  = g (fmap fst ba)  
+    a  = h ba             
+    (ba,s) = unzipF (fmap go t)  -- :: ( f (b,a) , f (Attr f c) )
+
+-- | Accumulating catamorphisms. Generalization of 'mapAccumR' from lists to trees.
+synthAccumCata :: Functor f => (f acc -> (acc,b)) -> Mu f -> (acc, Attr f b)
+synthAccumCata h = go where
+  go (Fix x) = (a, Fix (Ann b (fmap snd y))) where
+    y = fmap go x
+    (a,b) = h (fmap fst y)
+
+-- | Accumulating paramorphisms.  
+synthAccumPara :: Functor f => (Mu f -> f acc -> (acc,b)) -> Mu f -> (acc, Attr f b)
+synthAccumPara h = go where
+  go t@(Fix x) = (a, Fix (Ann b (fmap snd y))) where
+    y = fmap go x
+    (a,b) = h t (fmap fst y)
+
+-- | Could be a special case of 'synthAccumCata':
+--
+-- > mapAccumCata f == second (annZipWith (flip const)) . synthAccumCata (\(Ann b t) -> f b t) 
+-- >   where second g (x,y) = (x, g y)
+--
+mapAccumCata :: Functor f => (f acc -> b -> (acc,c)) -> Attr f b -> (acc, Attr f c)
+mapAccumCata h = go where
+  go (Fix (Ann b x)) = (acc, Fix (Ann c (fmap snd y))) where
+    y = fmap go x
+    (acc,c) = h (fmap fst y) b
+
+-- | Synonym for 'synthetiseM'. If you don't need the result, use 'cataM_' instead.
+synthCataM  ::  (Traversable f, Monad m) =>  (f a -> m a) -> Mu f -> m (Attr f a)
+synthCataM act = go where
   go (Fix x) = do
     y  <-  mapM go x    
     a  <-  act $ fmap attribute y
     return (Fix (Ann a y))
 
+-- | Monadic version of 'synthPara'. If you don't need the result,  use 'paraM_' instead.
+synthParaM  ::  (Traversable f, Monad m) => (Mu f -> f a -> m a) -> Mu f -> m (Attr f a)
+synthParaM act = go where
+  go t@(Fix x) = do
+    y  <-  mapM go x  
+    a  <-  act t $ fmap attribute y
+    return (Fix (Ann a y))
+
+-- | Monadic version of 'synthPara''. 
+synthParaM'  ::  (Traversable f, Monad m) =>  (f (Mu f, a) -> m a) -> Mu f -> m (Attr f a)
+synthParaM' act tree = liftM snd (go tree) where
+  go orig@(Fix x) = do 
+    uv <- mapM go x      
+    let lft = fmap (\(s,t) -> (s, attribute t)) uv
+    let rht = fmap snd uv 
+    a <- act lft
+    return ( orig , Fix $ Ann a rht ) 
+{-
+synthParaM' act = go where
+  go (Fix x) = do
+    y  <-  mapM go x    
+    a  <-  act $ unsafeZipWithF (,) x (fmap attribute y)
+    return (Fix (Ann a y))
+-}
+
 --------------------------------------------------------------------------------
 -- Inherited attributes
 
@@ -106,7 +253,7 @@ 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
+-- | Generalization of @scanl@ from lists to 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))
@@ -247,11 +394,19 @@ -- Tests
 #ifdef WITH_QUICKCHECK
 
+runtests_Attributes :: IO ()
 runtests_Attributes = do
   quickCheck prop_synthAccumL
   quickCheck prop_synthAccumR
   quickCheck prop_synthetise
- 
+  quickCheck prop_synthCata
+  quickCheck prop_synthPara
+  quickCheck prop_synthPara'
+  quickCheck prop_scanCata 
+  quickCheck prop_mapAccumCata
+  quickCheck prop_zygo
+  quickCheck prop_zygo_
+
 prop_synthAccumL :: FixT Label -> Bool
 prop_synthAccumL tree = 
   toList (Attrib (synthAccumL_ (\i _ -> (i+1,i)) 1 tree)) == [1..length (universe tree)]
@@ -267,7 +422,87 @@   map fold (universe tree)
   where
     fold = foldLeft (\s (Fix (TreeF (Label l) _)) -> s++l) []
+
+prop_synthCata :: FixT Label -> Bool
+prop_synthCata tree = attribute (synthCata f tree) == cata f tree where 
+  f :: TreeF Label String -> String
+  f (TreeF (Label label) xs) = label++"(" ++ intercalate "," xs ++ ")"
   
+prop_synthPara :: FixT Label -> Bool
+prop_synthPara tree = attribute (synthPara h tree) == para h tree where 
+  h :: FixT Label -> TreeF Label String -> String
+  h tree@(Fix (TreeF label ts)) ys = unLabel label++"_"++show siz++"(" ++ intercalate "," (zipWith c (toList ys) sizs) ++ ")" where
+    siz = cata f tree
+    sizs = map (cata f) ts
+    f t = 1 + Data.Foldable.sum t
+    c str j = str ++ "<" ++ show j ++ ">"
+
+prop_synthPara' :: FixT Label -> Bool
+prop_synthPara' tree = attribute (synthPara' g tree) == para' g tree where 
+  g :: TreeF Label (FixT Label , String) -> String
+  g (TreeF (Label label) xs) = label++"(" ++ intercalate "," (map u xs) ++ ")" where
+    u (tree,a) = show siz ++ "_" ++ a where
+      siz = cata (\t -> 1 + Data.Foldable.sum t) tree
+
+scanCataNaive :: Functor f => (a -> f b -> b) -> Attr f a -> Attr f b
+scanCataNaive f = annZipWith (flip const) . synthCata (\(Ann a x) -> f a x)
+
+prop_scanCata :: Attr (TreeF Label) String -> Bool
+prop_scanCata tree = scanCata f tree == scanCataNaive f tree where
+  f :: (String -> TreeF Label Integer -> Integer) -- -> Attr (TreeF Label) String -> Attr (TreeF Label) Integer
+  f str t = Prelude.product (toList t) + sumchar str
+  sumchar :: String -> Integer
+  sumchar = fromIntegral . Prelude.sum . map ord 
+--   tree = synthetise (\(TreeF (Label l) xs) -> map toUpper l ++ concat xs) tree) tree0
+
+mapAccumCataNaive :: Functor f => (f acc -> b -> (acc,c)) -> Attr f b -> (acc, Attr f c)
+mapAccumCataNaive f = second (annZipWith (flip const)) . synthAccumCata (\(Ann b t) -> f t b)
+
+prop_mapAccumCata :: Attr (TreeF Label) String -> Bool
+prop_mapAccumCata tree = mapAccumCata f tree == mapAccumCataNaive f tree where
+  f :: (TreeF Label Integer -> String -> (Integer,String)) -- -> Attr (TreeF Label) String -> Attr (TreeF Label) Integer
+  f t str = ( k - fromIntegral (length str) + sumchar str , "<" ++ show k ++ "," ++ str ++ ">") where 
+    ls = toList t
+    k  = Prelude.product ls
+  sumchar :: String -> Integer
+  sumchar = fromIntegral . Prelude.sum . map ord 
+  -- tree = synthetise (\(TreeF (Label l) xs) -> map toLower l ++ concat xs) tree) tree0
+
+--------------------------------------------------------------------------------
+-- Morphism tests which are here to avoid circular imports
+
+zygoNaive_ :: Functor f => (f b -> b) -> (f (b,a) -> a) -> Mu f -> a
+zygoNaive_ g h = para' (h . fmap (first attribute) . unAnn) . synthCata g 
+
+zygoNaive :: Functor f => (f b -> b) -> (f (b,a) -> a) -> Mu f -> (b,a)
+zygoNaive g h tree = (attribute tmp, para' h1 tmp) where 
+  tmp = synthCata g tree
+  h1 = h . fmap (first attribute) . unAnn
+
+prop_zygo :: FixT Label -> Bool
+prop_zygo tree = zygo g h tree == zygoNaive g h tree where
+  g :: TreeF Label Integer -> Integer
+  g (TreeF (Label label) child) = Prelude.product child + sumchar label
+
+  h :: TreeF Label (Integer,String) -> String
+  h (TreeF (Label label) child) = "[" ++ label ++ "]<" ++ intercalate "," (map f child) ++ ">"
+
+  f (k,s) = show k ++ "_" ++ s
+
+  sumchar = fromIntegral . Prelude.sum . map ord 
+
+prop_zygo_ :: FixT Label -> Bool
+prop_zygo_ tree = zygo_ g h tree == zygoNaive_ g h tree where
+  g :: TreeF Label Integer -> Integer
+  g (TreeF (Label label) child) = Prelude.product child + prodchar label
+
+  h :: TreeF Label (Integer,String) -> String
+  h (TreeF (Label label) child) = "<" ++ intercalate "," (map f child) ++ ">" ++ "[" ++ label ++ "]"
+
+  f (k,s) = s ++ "_" ++ show k
+
+  prodchar = fromIntegral . Prelude.product . map ord 
+
 #endif
 --------------------------------------------------------------------------------
 
Data/Generics/Fixplate/Base.hs view
@@ -32,8 +32,11 @@ -- | 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 functors.
+data Ann f a b  =  Ann 
+  { attr  :: a           -- ^ the annotation
+  , unAnn :: f b         -- ^ the original functor
+  }
 
 -- | Annotated fixed-point type.
 type Attr f a   =  Mu (Ann f a)
@@ -101,10 +104,15 @@ #endif
             
 --------------------------------------------------------------------------------
-        
+
+-- | NOTE: The 'EqF' instance for annotations compares both the annotations and the original part. 
 instance (Eq a, EqF f) => EqF (Ann f a) where 
   equalF (Ann a x) (Ann b y) = a == b && equalF x y
 
+-- | NOTE: The 'OrdF' instance for annotations first compares the /annotations/, and then 
+-- the functor part. If this is not the desired behaviour (it's not clear to me at the moment
+-- what is the good default here), you can use the standard newtype trick to define a new
+-- behaviour.
 instance (Ord a, OrdF f) => OrdF (Ann f a) where 
   compareF (Ann a x) (Ann b y) = case compare a b of
     LT -> LT
Data/Generics/Fixplate/Misc.hs view
@@ -5,8 +5,8 @@ --------------------------------------------------------------------------------
 
 import Prelude hiding (mapM,mapM_)
-import Control.Monad (liftM)
 import Data.Traversable
+--import Control.Monad (liftM)
 --import Control.Monad.Trans.State
 
 --------------------------------------------------------------------------------
@@ -39,6 +39,12 @@ 
 (<#>) :: (a -> b) -> (c -> d) -> (a,c) -> (b,d)
 (f <#> g) (x,y) = (f x, g y)
+
+first :: (a -> b) -> (a,c) -> (b,c)
+first f (x,y) = (f x, y)
+
+second :: (b -> c) -> (a,b) -> (a,c)
+second g (x,y) = (x, g y)
 
 --------------------------------------------------------------------------------
 
Data/Generics/Fixplate/Morphisms.hs view
@@ -6,22 +6,28 @@ 
 --------------------------------------------------------------------------------
 
+import Prelude hiding ( mapM )
 import Data.Foldable
+import Data.Traversable
 import Data.Generics.Fixplate.Base
 
 #ifdef WITH_QUICKCHECK
+import Data.Char ( ord )
+import Data.List ( intercalate )
 import Test.QuickCheck
 import Data.Generics.Fixplate.Traversals
 import Data.Generics.Fixplate.Test.Tools
 #endif 
 
 --------------------------------------------------------------------------------
+-- * Classic ana\/cata\/para\/hylo-morphisms
 
 -- | 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) 
 
+-- | Another version of 'para' (more natural in some sense; compare with 'apo').
 para' :: Functor f => (f (Mu f, a) -> a) -> Mu f -> a
 para' h = go where
   go (Fix t) = h (fmap go' $ t)
@@ -36,15 +42,120 @@ cata h = go where
   go = h . fmap go . unFix
 
--- | An /anamorphism/ is simply an unfold.
+-- | An /anamorphism/ is simply an unfold. Probably not very useful in this context.
 ana :: Functor f => (a -> f a) -> a -> Mu f
 ana h = go where
   go = Fix . fmap go . h
   -- go x = Fix (fmap go (h x))
 
+-- | An /apomorphism/ is a generalization of the anamorphism.
+apo :: Functor f => (a -> f (Either (Mu f) a)) -> a -> Mu f
+apo h = go where
+  go = Fix . fmap worker . h 
+  worker ei = case ei of 
+    Left  t -> t
+    Right a -> go a
+
 -- | 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
 
 --------------------------------------------------------------------------------
+-- * More exotic stuff
 
+-- | A /zygomorphism/ is a basically a catamorphism inside another catamorphism.
+-- It could be implemented (somewhat wastefully) by first annotating each subtree
+-- with the corresponding values of the inner catamorphism ('synthCata'), then running 
+-- a paramorphims on the annotated tree:
+-- 
+-- > zygo_ g h == para' u . synthCata g 
+-- >   where
+-- >     u = h . fmap (first attribute) . unAnn
+-- >     first f (x,y) = (f x, y)
+--
+zygo_ :: Functor f => (f b -> b) -> (f (b,a) -> a) -> Mu f -> a
+zygo_ g h = snd . zygo g h  
+
+zygo :: Functor f => (f b -> b) -> (f (b,a) -> a) -> Mu f -> (b,a)
+zygo g h = go where
+  go (Fix t) = (b,a) where
+    b  = g (fmap fst ba)  -- :: b
+    a  = h ba             -- :: a
+    ba = fmap go t        -- :: f (b,a)
+
+newtype Free   f a = Free   { unFree   :: Either a (f (Free f a)) }
+newtype CoFree f a = CoFree { unCoFree :: (a , f (CoFree f a))    }
+
+-- | Futumorphism. Whatever it does.
+futu :: Functor f => (a -> f (Free f a)) -> a -> Mu f
+futu h = go where
+  -- go :: a -> Mu f
+  go = Fix . fmap worker . h 
+  -- worker :: Free f a -> Mu f
+  worker (Free ei) = case ei of
+    Left  x -> go x
+    Right t -> Fix (fmap worker t)
+
+-- | Histomorphism. Whatever it does.
+histo :: Functor f => (f (CoFree f a) -> a) -> Mu f -> a
+histo h = go where
+  -- go :: Mu f -> a
+  go = h . fmap worker . unFix
+  -- worker :: Mu f -> CoFree f
+  worker t@(Fix s) = CoFree ( go t , fmap worker s )
+
+--------------------------------------------------------------------------------
+-- * Monadic versions
+
+-- | Monadic paramorphism.
+paraM :: (Monad m, Traversable f) => (Mu f -> f a -> m a) -> Mu f -> m a
+paraM h = go where
+  go t = mapM go (unFix t) >>= h t
+
+paraM_ :: (Monad m, Traversable f) => (Mu f -> f a -> m a) -> Mu f -> m ()
+paraM_ h t = do { _ <- paraM h t ; return () }
+
+-- | Monadic catamorphism.
+cataM :: (Monad m, Traversable f) => (f a -> m a) -> Mu f -> m a
+cataM h = go where
+  go (Fix t) = mapM go t >>= h
+
+cataM_ :: (Monad m, Traversable f) => (f a -> m a) -> Mu f -> m ()
+cataM_ h t = do { _ <- cataM h t ; return () }
+
+--------------------------------------------------------------------------------
+#ifdef WITH_QUICKCHECK
+-- * Tests
+
+runtests_Morphisms :: IO ()
+runtests_Morphisms = do
+  quickCheck prop_para
+  quickCheck prop_paraList
+  -- quickCheck prop_zygo      -- moved to Attributes.hs, to avoid circular imports
+  -- quickCheck prop_zygo_
+ 
+prop_para :: FixT Label -> Bool
+prop_para tree = para f tree == para' f' tree where
+  f :: FixT Label -> TreeF Label Integer -> Integer
+  f t@(Fix (TreeF (Label label) sub)) js = h label (toList sub) (toList js)
+
+  f' :: TreeF Label (FixT Label, Integer) -> Integer
+  f' t@(TreeF (Label label) subjs) = h label sub js where
+    (sub,js) = unzip $ toList t
+
+  h :: String -> [FixT Label] -> [Integer] -> Integer
+  h label ts js = Prelude.sum $ zipWith (*) [3..] (map (fi.ord) label ++ map g ts ++ js)
+  g (Fix (TreeF (Label label) _)) = (Prelude.sum (map (fi.ord) label)) `mod` 59
+
+  fi = fromIntegral :: Int -> Integer
+
+prop_paraList :: FixT Label -> Bool
+prop_paraList tree = para f tree == paraList flist tree where
+  f t s = flist t (toList s)
+  flist :: FixT Label -> [Integer] -> Integer
+  flist t@(Fix (TreeF (Label label) sub)) js = Prelude.sum $ zipWith (*) [4..] (map (fi.ord) label ++ js)
+
+  fi = fromIntegral :: Int -> Integer
+
+#endif
+--------------------------------------------------------------------------------
Data/Generics/Fixplate/Open.hs view
@@ -50,7 +50,7 @@ 
 -- | The children together with functions replacing that particular child.    
 holes :: Traversable f => f a -> f (a, a -> f a)
-holes tree = mapAccumL_ ithHole 0 tree where
+holes tree = mapAccumL_ ithHole (0::Int) tree where
   ithHole i x = (i+1, (x,h)) where          
     h y = mapAccumL_ g 0 tree where         
       g j z = (j+1, if i==j then y else z)  
@@ -69,6 +69,7 @@ builder :: Traversable f => f a -> [b] -> f b
 builder tree xs = mapAccumL_ g xs tree where
   g (x:xs) _ = (xs,x)
+  g _ _ = error "Open/builder: shouldn't happen"
 
 --------------------------------------------------------------------------------
 
@@ -153,6 +154,7 @@ unsafeZipWithF f x y = z where
   z = mapAccumL_ g (toList y) x
   g (b:bs) a = (bs, f a b)
+  g _ _ = error "Open/unsafeZipWithF: shouldn't happen"
 
 --------------------------------------------------------------------------------
 
@@ -166,6 +168,7 @@ unsafeZipWithFM :: (Traversable f, Monad m) => (a -> b -> m c) -> f a -> f b -> m (f c)
 unsafeZipWithFM f x y = liftM snd $ mapAccumM g (toList y) x where
   g (b:bs) a = f a b >>= \r -> return (bs, r)
+  g _ _ = error "Open/unsafeZipWithFM: shouldn't happen"
 
 --------------------------------------------------------------------------------
 
Data/Generics/Fixplate/Tests.hs view
@@ -26,5 +26,6 @@   putStrLn "tests for traversals..."      ; runtests_Traversals
   putStrLn "tests for Attributes..."      ; runtests_Attributes
   putStrLn "tests for zippers..."         ; runtests_Zipper
+  putStrLn "tests for morphisms..."       ; runtests_Morphisms
 
 --------------------------------------------------------------------------------
Data/Generics/Fixplate/Traversals.hs view
@@ -13,7 +13,7 @@ 
 import Data.Generics.Fixplate.Base 
 import Data.Generics.Fixplate.Open
-import Data.Generics.Fixplate.Misc
+--import Data.Generics.Fixplate.Misc
 
 #ifdef WITH_QUICKCHECK
 import Test.QuickCheck
@@ -123,6 +123,7 @@ universeNaive :: Foldable f => Mu f -> [Mu f]
 universeNaive x = x : concatMap universeNaive (children x)
 
+runtests_Traversals :: IO ()
 runtests_Traversals = do
   quickCheck prop_leftFold
   quickCheck prop_leftFoldLazy
Data/Generics/Fixplate/Zipper.hs view
@@ -21,11 +21,11 @@ import Data.Generics.Fixplate.Base
 import Data.Generics.Fixplate.Open
 import Data.Generics.Fixplate.Misc
-import Data.Generics.Fixplate.Traversals
 
 #ifdef WITH_QUICKCHECK
 import Test.QuickCheck
 import Data.Generics.Fixplate.Attributes
+import Data.Generics.Fixplate.Traversals
 import Data.Generics.Fixplate.Test.Tools
 import Control.Monad (liftM)
 #endif 
@@ -476,6 +476,7 @@   
 --------------------------------------------------------------------------------
 
+runtests_Zipper :: IO ()
 runtests_Zipper = do
   quickCheck prop_ReadShowLoc
   quickCheck prop_findLoc
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2011, Balazs Komuves+Copyright (c) 2011-2012, Balazs Komuves All rights reserved.  Redistribution and use in source and binary forms, with or without
fixplate.cabal view
@@ -1,11 +1,11 @@  Name:                fixplate-Version:             0.1.2-Synopsis:            Uniplate-style generic traversals for fixed-point types, with some extras.+Version:             0.1.3+Synopsis:            Uniplate-style generic traversals for optionally annotated fixed-point types. 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.+                     optionally annotated with attributes. We also provide recursion schemes,+                     and 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@@ -15,8 +15,12 @@ Stability:           Experimental Category:            Generics Tested-With:         GHC == 7.0.3-Cabal-Version:       >= 1.2+Cabal-Version:       >= 1.6 Build-Type:          Simple++source-repository head+  type:     darcs+  location: http://code.haskell.org/~bkomuves/projects/fixplate/  Flag withQuickCheck   Description: Compile with the QuickCheck tests.