{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Retrie.SYB
( everywhereMWithContextBut
, GenericCU
, GenericMC
, Strategy
, topDown
, bottomUp
, everythingMWithContextBut
, GenericMCQ
, module Data.Generics
) where
import Control.Monad
import Data.Generics hiding (Fixity(..))
type GenericMC m c = forall a. Data a => c -> a -> m a
type GenericCU m c = forall a. Data a => c -> Int -> a -> m c
everywhereMWithContextBut
:: forall m c. Monad m
=> Strategy m
-> GenericQ Bool
-> GenericCU m c
-> GenericMC m c
-> GenericMC m c
everywhereMWithContextBut strategy stop upd f = go
where
go :: GenericMC m c
go ctxt x
| stop x = return x
| otherwise = strategy (f ctxt) (h ctxt) x
h ctxt parent = gforMIndexed parent $ \i child -> do
ctxt' <- upd ctxt i parent
go ctxt' child
type GenericMCQ m c r = forall a. Data a => c -> a -> m r
everythingMWithContextBut
:: forall m c r. (Monad m, Monoid r)
=> GenericQ Bool
-> GenericCU m c
-> GenericMCQ m c r
-> GenericMCQ m c r
everythingMWithContextBut stop upd q = go
where
go :: GenericMCQ m c r
go ctxt x
| stop x = return mempty
| otherwise = do
r <- q ctxt x
rs <- gforQIndexed x $ \i child -> do
ctxt' <- upd ctxt i x
go ctxt' child
return $ mconcat (r:rs)
type Strategy m = forall a. Monad m => (a -> m a) -> (a -> m a) -> a -> m a
topDown :: Strategy m
topDown p cs = p >=> cs
bottomUp :: Strategy m
bottomUp p cs = cs >=> p
gforMIndexed
:: (Monad m, Data a) => a -> (forall d. Data d => Int -> d -> m d) -> m a
gforMIndexed x f = snd (gmapAccumM (accumIndex f) (-1) x)
accumIndex :: (Int -> a -> b) -> Int -> a -> (Int, b)
accumIndex f i y = let !i' = i+1 in (i', f i' y)
gforQIndexed
:: (Monad m, Data a) => a -> (forall d. Data d => Int -> d -> m r) -> m [r]
gforQIndexed x f = sequence $ snd $ gmapAccumQ (accumIndex f) (-1) x