@@ -18,6 +18,7 @@
18module Data.Generics.Extras where
18module Data.Generics.Extras where
20import Data.Data
20import Data.Data
21+import Data.Maybe (fromMaybe)
23-- Apply a top-down monadic transformation everywhere
24-- Apply a top-down monadic transformation everywhere
@@ -26,3 +27,37 @@ everywhereM' :: (Monad m, Data d) => (forall d1. (Data d1) => d1 -> m d1) -> d -
26everywhereM' f x = do
27everywhereM' f x = do
28 gmapM (everywhereM' f) y
29 gmapM (everywhereM' f) y
32+-- Apply a top-down transformation, mutating a state when descending from parents to children
34+-- For example, if we want to relabel bound variables with a different data constructor, we can do so:
36+-- > data Expr = Var String
37+-- > | Lam String Test
39+-- > | LocalVar String deriving (Show, Data, Typeable)
41+-- > test = App (Lam "a" (App (Var "a") (Var "b"))) (Var "a")
43+-- > varsToLocals :: Expr -> Expr
44+-- > varsToLocals = everywhereWithContext' [] (mkS go)
46+-- > go locals (Var v) | v `elem` locals = (locals, LocalVar v)
47+-- > go locals lam@(Lam local _) = (local : locals, lam)
48+-- > go locals other = (locals, other)
50+everywhereWithContext' :: (Data d) => s -> (forall d1. (Data d1) => s -> d1 -> (s, d1)) -> d -> d
51+everywhereWithContext' s0 f x =
52+ let (s, y) = f s0 x in
53+ gmapT (everywhereWithContext' s f) y
56+-- Make a stateful transformation function
58+mkS :: (Data a, Data b) => (s -> a -> (s, a)) -> s -> b -> (s, b)
59+mkS f s b = fromMaybe (s, b) $ do