{-# LANGUAGE RankNTypes, ScopedTypeVariables, CPP #-}
module Data.Generics.Schemes (
everywhere,
everywhere',
everywhereBut,
everywhereM,
somewhere,
everything,
everythingBut,
everythingWithContext,
listify,
something,
synthesize,
gsize,
glength,
gdepth,
gcount,
gnodecount,
gtypecount,
gfindtype
) where
#ifdef __HADDOCK__
import Prelude
#endif
import Data.Data
import Data.Generics.Aliases
import Control.Monad
everywhere :: (forall a. Data a => a -> a)
-> (forall a. Data a => a -> a)
everywhere f = f . gmapT (everywhere f)
everywhere' :: (forall a. Data a => a -> a)
-> (forall a. Data a => a -> a)
everywhere' f = gmapT (everywhere' f) . f
everywhereBut :: GenericQ Bool -> GenericT -> GenericT
everywhereBut q f x
| q x = x
| otherwise = f (gmapT (everywhereBut q f) x)
everywhereM :: Monad m => GenericM m -> GenericM m
everywhereM f x = do x' <- gmapM (everywhereM f) x
f x'
somewhere :: MonadPlus m => GenericM m -> GenericM m
somewhere f x = f x `mplus` gmapMp (somewhere f) x
everything :: (r -> r -> r) -> GenericQ r -> GenericQ r
everything k f x = foldl k (f x) (gmapQ (everything k f) x)
everythingBut :: (r -> r -> r) -> GenericQ (r, Bool) -> GenericQ r
everythingBut k f x = let (v, stop) = f x
in if stop
then v
else foldl k v (gmapQ (everythingBut k f) x)
everythingWithContext :: s -> (r -> r -> r) -> GenericQ (s -> (r, s)) -> GenericQ r
everythingWithContext s0 f q x =
foldl f r (gmapQ (everythingWithContext s' f q) x)
where (r, s') = q x s0
listify :: Typeable r => (r -> Bool) -> GenericQ [r]
listify p = everything (++) ([] `mkQ` (\x -> if p x then [x] else []))
something :: GenericQ (Maybe u) -> GenericQ (Maybe u)
something = everything orElse
synthesize :: s -> (t -> s -> s) -> GenericQ (s -> t) -> GenericQ t
synthesize z o f x = f x (foldr o z (gmapQ (synthesize z o f) x))
gsize :: Data a => a -> Int
gsize t = 1 + sum (gmapQ gsize t)
glength :: GenericQ Int
glength = length . gmapQ (const ())
gdepth :: GenericQ Int
gdepth = (+) 1 . foldr max 0 . gmapQ gdepth
gcount :: GenericQ Bool -> GenericQ Int
gcount p = everything (+) (\x -> if p x then 1 else 0)
gnodecount :: GenericQ Int
gnodecount = gcount (const True)
gtypecount :: Typeable a => a -> GenericQ Int
gtypecount (_::a) = gcount (False `mkQ` (\(_::a) -> True))
gfindtype :: (Data x, Typeable y) => x -> Maybe y
gfindtype = singleton
. foldl unJust []
. gmapQ (Nothing `mkQ` Just)
where
unJust l (Just x) = x:l
unJust l Nothing = l
singleton [s] = Just s
singleton _ = Nothing