{-# LANGUAGE RankNTypes, ScopedTypeVariables, CPP #-}
module Data.Generics.Twins (
gfoldlAccum,
gmapAccumT,
gmapAccumM,
gmapAccumQl,
gmapAccumQr,
gmapAccumQ,
gmapAccumA,
gzipWithT,
gzipWithM,
gzipWithQ,
geq,
gzip,
gcompare
) where
#ifdef __HADDOCK__
import Prelude
#endif
import Data.Data
import Data.Generics.Aliases
#ifdef __GLASGOW_HASKELL__
import Prelude hiding ( GT )
#endif
#if __GLASGOW_HASKELL__ < 709
import Control.Applicative (Applicative(..))
import Data.Monoid ( mappend, mconcat )
#endif
gfoldlAccum :: Data d
=> (forall e r. Data e => a -> c (e -> r) -> e -> (a, c r))
-> (forall g. a -> g -> (a, c g))
-> a -> d -> (a, c d)
gfoldlAccum k z a0 d = unA (gfoldl k' z' d) a0
where
k' c y = A (\a -> let (a', c') = unA c a in k a' c' y)
z' f = A (\a -> z a f)
newtype A a c d = A { unA :: a -> (a, c d) }
gmapAccumT :: Data d
=> (forall e. Data e => a -> e -> (a,e))
-> a -> d -> (a, d)
gmapAccumT f a0 d0 = let (a1, d1) = gfoldlAccum k z a0 d0
in (a1, unID d1)
where
k a (ID c) d = let (a',d') = f a d
in (a', ID (c d'))
z a x = (a, ID x)
gmapAccumA :: forall b d a. (Data d, Applicative a)
=> (forall e. Data e => b -> e -> (b, a e))
-> b -> d -> (b, a d)
gmapAccumA f a0 d0 = gfoldlAccum k z a0 d0
where
k :: forall d' e. (Data d') =>
b -> a (d' -> e) -> d' -> (b, a e)
k a c d = let (a',d') = f a d
c' = c <*> d'
in (a', c')
z :: forall t c a'. (Applicative a') =>
t -> c -> (t, a' c)
z a x = (a, pure x)
gmapAccumM :: (Data d, Monad m)
=> (forall e. Data e => a -> e -> (a, m e))
-> a -> d -> (a, m d)
gmapAccumM f = gfoldlAccum k z
where
k a c d = let (a',d') = f a d
in (a', d' >>= \d'' -> c >>= \c' -> return (c' d''))
z a x = (a, return x)
gmapAccumQl :: Data d
=> (r -> r' -> r)
-> r
-> (forall e. Data e => a -> e -> (a,r'))
-> a -> d -> (a, r)
gmapAccumQl o r0 f a0 d0 = let (a1, r1) = gfoldlAccum k z a0 d0
in (a1, unCONST r1)
where
k a (CONST c) d = let (a', r) = f a d
in (a', CONST (c `o` r))
z a _ = (a, CONST r0)
gmapAccumQr :: Data d
=> (r' -> r -> r)
-> r
-> (forall e. Data e => a -> e -> (a,r'))
-> a -> d -> (a, r)
gmapAccumQr o r0 f a0 d0 = let (a1, l) = gfoldlAccum k z a0 d0
in (a1, unQr l r0)
where
k a (Qr c) d = let (a',r') = f a d
in (a', Qr (\r -> c (r' `o` r)))
z a _ = (a, Qr id)
gmapAccumQ :: Data d
=> (forall e. Data e => a -> e -> (a,q))
-> a -> d -> (a, [q])
gmapAccumQ f = gmapAccumQr (:) [] f
newtype ID x = ID { unID :: x }
newtype CONST c a = CONST { unCONST :: c }
newtype Qr r a = Qr { unQr :: r -> r }
gzipWithT :: GenericQ (GenericT) -> GenericQ (GenericT)
gzipWithT f x y = case gmapAccumT perkid funs y of
([], c) -> c
_ -> error "gzipWithT"
where
perkid a d = (tail a, unGT (head a) d)
funs = gmapQ (\k -> GT (f k)) x
gzipWithM :: Monad m => GenericQ (GenericM m) -> GenericQ (GenericM m)
gzipWithM f x y = case gmapAccumM perkid funs y of
([], c) -> c
_ -> error "gzipWithM"
where
perkid a d = (tail a, unGM (head a) d)
funs = gmapQ (\k -> GM (f k)) x
gzipWithQ :: GenericQ (GenericQ r) -> GenericQ (GenericQ [r])
gzipWithQ f x y = case gmapAccumQ perkid funs y of
([], r) -> r
_ -> error "gzipWithQ"
where
perkid a d = (tail a, unGQ (head a) d)
funs = gmapQ (\k -> GQ (f k)) x
geq :: Data a => a -> a -> Bool
geq x0 y0 = geq' x0 y0
where
geq' :: GenericQ (GenericQ Bool)
geq' x y = (toConstr x == toConstr y)
&& and (gzipWithQ geq' x y)
gzip :: GenericQ (GenericM Maybe) -> GenericQ (GenericM Maybe)
gzip f = go
where
go :: GenericQ (GenericM Maybe)
go x y =
f x y
`orElse`
if toConstr x == toConstr y
then gzipWithM go x y
else Nothing
gcompare :: Data a => a -> a -> Ordering
gcompare = gcompare'
where
gcompare' :: (Data a, Data b) => a -> b -> Ordering
gcompare' x y
= let repX = constrRep $ toConstr x
repY = constrRep $ toConstr y
in
case (repX, repY) of
(AlgConstr nX, AlgConstr nY) ->
nX `compare` nY `mappend` mconcat (gzipWithQ gcompare' x y)
(IntConstr iX, IntConstr iY) -> iX `compare` iY
(FloatConstr rX, FloatConstr rY) -> rX `compare` rY
(CharConstr cX, CharConstr cY) -> cX `compare` cY
_ -> error "type incompatibility in gcompare"