    {-# LANGUAGE RankNTypes, ScopedTypeVariables, CPP #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Data.Generics.Twins
    -- Copyright   :  (c) The University of Glasgow, CWI 2001--2004
    -- License     :  BSD-style (see the LICENSE file)
    --
    -- Maintainer  :  generics@haskell.org
    -- Stability   :  experimental
    -- Portability :  non-portable (local universal quantification)
    --
    -- \"Scrap your boilerplate\" --- Generic programming in Haskell
    -- See <http://www.cs.uu.nl/wiki/GenericProgramming/SYB>. The present module
    -- provides support for multi-parameter traversal, which is also
    -- demonstrated with generic operations like equality.
    --
    -----------------------------------------------------------------------------

    module Data.Generics.Twins (

            -- * Generic folds and maps that also accumulate
            gfoldlAccum,
            gmapAccumT,
            gmapAccumM,
            gmapAccumQl,
            gmapAccumQr,
            gmapAccumQ,
            gmapAccumA,

            -- * Mapping combinators for twin traversal
            gzipWithT,
            gzipWithM,
            gzipWithQ,

            -- * Typical twin traversals
            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

    ------------------------------------------------------------------------------

    ------------------------------------------------------------------------------
    --
    --      Generic folds and maps that also accumulate
    --
    ------------------------------------------------------------------------------

    {--------------------------------------------------------------

    A list map can be elaborated to perform accumulation.
    In the same sense, we can elaborate generic maps over terms.

    We recall the type of map:
    map :: (a -> b) -> [a] -> [b]

    We recall the type of an accumulating map (see Data.List):
    mapAccumL :: (a -> b -> (a,c)) -> a -> [b] -> (a,[c])

    Applying the same scheme we obtain an accumulating gfoldl.

    --------------------------------------------------------------}

    -- | gfoldl with accumulation

    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 :: (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 :: forall e r. Data e => a -> c (e -> r) -> e -> (a, c r)
    k z :: forall g. a -> g -> (a, c g)
    z a0 :: a
    a0 d :: d
    d = A a c d -> a -> (a, c d)
    forall a (c :: * -> *) d. A a c d -> a -> (a, c d)
    unA ((forall d b. Data d => A a c (d -> b) -> d -> A a c b)
    -> (forall g. g -> A a c g) -> d -> A a c d
    forall a (c :: * -> *).
    Data a =>
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a
    gfoldl forall d b. Data d => A a c (d -> b) -> d -> A a c b
    k' forall g. g -> A a c g
    z' d
    d) a
    a0
     where
      k' :: A a c (e -> d) -> e -> A a c d
    k' c :: A a c (e -> d)
    c y :: e
    y = (a -> (a, c d)) -> A a c d
    forall a (c :: * -> *) d. (a -> (a, c d)) -> A a c d
    A (\a :: a
    a -> let (a' :: a
    a', c' :: c (e -> d)
    c') = A a c (e -> d) -> a -> (a, c (e -> d))
    forall a (c :: * -> *) d. A a c d -> a -> (a, c d)
    unA A a c (e -> d)
    c a
    a in a -> c (e -> d) -> e -> (a, c d)
    forall e r. Data e => a -> c (e -> r) -> e -> (a, c r)
    k a
    a' c (e -> d)
    c' e
    y)
      z' :: d -> A a c d
    z' f :: d
    f   = (a -> (a, c d)) -> A a c d
    forall a (c :: * -> *) d. (a -> (a, c d)) -> A a c d
    A (\a :: a
    a -> a -> d -> (a, c d)
    forall g. a -> g -> (a, c g)
    z a
    a d
    f)

    -- | A type constructor for accumulation
    newtype A a c d = A { A a c d -> a -> (a, c d)
    unA :: a -> (a, c d) }

    -- | gmapT with accumulation
    gmapAccumT :: Data d
               => (forall e. Data e => a -> e -> (a,e))
               -> a -> d -> (a, d)
    gmapAccumT :: (forall e. Data e => a -> e -> (a, e)) -> a -> d -> (a, d)
    gmapAccumT f :: forall e. Data e => a -> e -> (a, e)
    f a0 :: a
    a0 d0 :: d
    d0 = let (a1 :: a
    a1, d1 :: ID d
    d1) = (forall e r. Data e => a -> ID (e -> r) -> e -> (a, ID r))
    -> (forall g. a -> g -> (a, ID g)) -> a -> d -> (a, ID d)
    forall d a (c :: * -> *).
    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 forall e r. Data e => a -> ID (e -> r) -> e -> (a, ID r)
    k forall g. a -> g -> (a, ID g)
    forall a x. a -> x -> (a, ID x)
    z a
    a0 d
    d0
                         in (a
    a1, ID d -> d
    forall x. ID x -> x
    unID ID d
    d1)
     where
      k :: a -> ID (t -> x) -> t -> (a, ID x)
    k a :: a
    a (ID c :: t -> x
    c) d :: t
    d = let (a' :: a
    a',d' :: t
    d') = a -> t -> (a, t)
    forall e. Data e => a -> e -> (a, e)
    f a
    a t
    d
                      in (a
    a', x -> ID x
    forall x. x -> ID x
    ID (t -> x
    c t
    d'))
      z :: a -> x -> (a, ID x)
    z a :: a
    a x :: x
    x = (a
    a, x -> ID x
    forall x. x -> ID x
    ID x
    x)

    -- | Applicative version
    gmapAccumA :: forall b d a. (Data d, Applicative a)
               => (forall e. Data e => b -> e -> (b, a e))
               -> b -> d -> (b, a d)
    gmapAccumA :: (forall e. Data e => b -> e -> (b, a e)) -> b -> d -> (b, a d)
    gmapAccumA f :: forall e. Data e => b -> e -> (b, a e)
    f a0 :: b
    a0 d0 :: d
    d0 = (forall e r. Data e => b -> a (e -> r) -> e -> (b, a r))
    -> (forall g. b -> g -> (b, a g)) -> b -> d -> (b, a d)
    forall d a (c :: * -> *).
    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 forall e r. Data e => b -> a (e -> r) -> e -> (b, a r)
    k forall g. b -> g -> (b, a g)
    forall t c (a' :: * -> *). Applicative a' => t -> c -> (t, a' c)
    z b
    a0 d
    d0
        where
          k :: forall d' e. (Data d') =>
               b -> a (d' -> e) -> d' -> (b, a e)
          k :: b -> a (d' -> e) -> d' -> (b, a e)
    k a :: b
    a c :: a (d' -> e)
    c d :: d'
    d = let (a' :: b
    a',d' :: a d'
    d') = b -> d' -> (b, a d')
    forall e. Data e => b -> e -> (b, a e)
    f b
    a d'
    d
                        c' :: a e
    c' = a (d' -> e)
    c a (d' -> e) -> a d' -> a e
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> a d'
    d'
                    in (b
    a', a e
    c')
          z :: forall t c a'. (Applicative a') =>
               t -> c -> (t, a' c)
          z :: t -> c -> (t, a' c)
    z a :: t
    a x :: c
    x = (t
    a, c -> a' c
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure c
    x)

    -- | gmapM with accumulation
    gmapAccumM :: (Data d, Monad m)
               => (forall e. Data e => a -> e -> (a, m e))
               -> a -> d -> (a, m d)
    gmapAccumM :: (forall e. Data e => a -> e -> (a, m e)) -> a -> d -> (a, m d)
    gmapAccumM f :: forall e. Data e => a -> e -> (a, m e)
    f = (forall e r. Data e => a -> m (e -> r) -> e -> (a, m r))
    -> (forall g. a -> g -> (a, m g)) -> a -> d -> (a, m d)
    forall d a (c :: * -> *).
    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 forall e r. Data e => a -> m (e -> r) -> e -> (a, m r)
    k forall g. a -> g -> (a, m g)
    forall (m :: * -> *) a a. Monad m => a -> a -> (a, m a)
    z
     where
      k :: a -> m (t -> b) -> t -> (a, m b)
    k a :: a
    a c :: m (t -> b)
    c d :: t
    d = let (a' :: a
    a',d' :: m t
    d') = a -> t -> (a, m t)
    forall e. Data e => a -> e -> (a, m e)
    f a
    a t
    d
                 in (a
    a', m t
    d' m t -> (t -> m b) -> m b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \d'' :: t
    d'' -> m (t -> b)
    c m (t -> b) -> ((t -> b) -> m b) -> m b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \c' :: t -> b
    c' -> b -> m b
    forall (m :: * -> *) a. Monad m => a -> m a
    return (t -> b
    c' t
    d''))
      z :: a -> a -> (a, m a)
    z a :: a
    a x :: a
    x = (a
    a, a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    x)

    -- | gmapQl with accumulation
    gmapAccumQl :: Data d
                => (r -> r' -> r)
                -> r
                -> (forall e. Data e => a -> e -> (a,r'))
                -> a -> d -> (a, r)
    gmapAccumQl :: (r -> r' -> r)
    -> r -> (forall e. Data e => a -> e -> (a, r')) -> a -> d -> (a, r)
    gmapAccumQl o :: r -> r' -> r
    o r0 :: r
    r0 f :: forall e. Data e => a -> e -> (a, r')
    f a0 :: a
    a0 d0 :: d
    d0 = let (a1 :: a
    a1, r1 :: CONST r d
    r1) = (forall e r.
     Data e =>
     a -> CONST r (e -> r) -> e -> (a, CONST r r))
    -> (forall g. a -> g -> (a, CONST r g)) -> a -> d -> (a, CONST r d)
    forall d a (c :: * -> *).
    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 forall e r. Data e => a -> CONST r (e -> r) -> e -> (a, CONST r r)
    forall e a a. Data e => a -> CONST r a -> e -> (a, CONST r a)
    k forall g. a -> g -> (a, CONST r g)
    forall a p a. a -> p -> (a, CONST r a)
    z a
    a0 d
    d0
                               in (a
    a1, CONST r d -> r
    forall c a. CONST c a -> c
    unCONST CONST r d
    r1)
     where
      k :: a -> CONST r a -> e -> (a, CONST r a)
    k a :: a
    a (CONST c :: r
    c) d :: e
    d = let (a' :: a
    a', r :: r'
    r) = a -> e -> (a, r')
    forall e. Data e => a -> e -> (a, r')
    f a
    a e
    d
                         in (a
    a', r -> CONST r a
    forall c a. c -> CONST c a
    CONST (r
    c r -> r' -> r
    `o` r'
    r))
      z :: a -> p -> (a, CONST r a)
    z a :: a
    a _ = (a
    a, r -> CONST r a
    forall c a. c -> CONST c a
    CONST r
    r0)

    -- | gmapQr with accumulation
    gmapAccumQr :: Data d
                => (r' -> r -> r)
                -> r
                -> (forall e. Data e => a -> e -> (a,r'))
                -> a -> d -> (a, r)
    gmapAccumQr :: (r' -> r -> r)
    -> r -> (forall e. Data e => a -> e -> (a, r')) -> a -> d -> (a, r)
    gmapAccumQr o :: r' -> r -> r
    o r0 :: r
    r0 f :: forall e. Data e => a -> e -> (a, r')
    f a0 :: a
    a0 d0 :: d
    d0 = let (a1 :: a
    a1, l :: Qr r d
    l) = (forall e r. Data e => a -> Qr r (e -> r) -> e -> (a, Qr r r))
    -> (forall g. a -> g -> (a, Qr r g)) -> a -> d -> (a, Qr r d)
    forall d a (c :: * -> *).
    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 forall e r. Data e => a -> Qr r (e -> r) -> e -> (a, Qr r r)
    forall e a a. Data e => a -> Qr r a -> e -> (a, Qr r a)
    k forall g. a -> g -> (a, Qr r g)
    forall a p r a. a -> p -> (a, Qr r a)
    z a
    a0 d
    d0
                               in (a
    a1, Qr r d -> r -> r
    forall r a. Qr r a -> r -> r
    unQr Qr r d
    l r
    r0)
     where
      k :: a -> Qr r a -> e -> (a, Qr r a)
    k a :: a
    a (Qr c :: r -> r
    c) d :: e
    d = let (a' :: a
    a',r' :: r'
    r') = a -> e -> (a, r')
    forall e. Data e => a -> e -> (a, r')
    f a
    a e
    d
                      in (a
    a', (r -> r) -> Qr r a
    forall r a. (r -> r) -> Qr r a
    Qr (\r :: r
    r -> r -> r
    c (r'
    r' r' -> r -> r
    `o` r
    r)))
      z :: a -> p -> (a, Qr r a)
    z a :: a
    a _ = (a
    a, (r -> r) -> Qr r a
    forall r a. (r -> r) -> Qr r a
    Qr r -> r
    forall a. a -> a
    id)

    -- | gmapQ with accumulation
    gmapAccumQ :: Data d
               => (forall e. Data e => a -> e -> (a,q))
               -> a -> d -> (a, [q])
    gmapAccumQ :: (forall e. Data e => a -> e -> (a, q)) -> a -> d -> (a, [q])
    gmapAccumQ f :: forall e. Data e => a -> e -> (a, q)
    f = (q -> [q] -> [q])
    -> [q]
    -> (forall e. Data e => a -> e -> (a, q))
    -> a
    -> d
    -> (a, [q])
    forall d r' r a.
    Data d =>
    (r' -> r -> r)
    -> r -> (forall e. Data e => a -> e -> (a, r')) -> a -> d -> (a, r)
    gmapAccumQr (:) [] forall e. Data e => a -> e -> (a, q)
    f

    ------------------------------------------------------------------------------
    --
    --      Helper type constructors
    --
    ------------------------------------------------------------------------------

    -- | The identity type constructor needed for the definition of gmapAccumT
    newtype ID x = ID { ID x -> x
    unID :: x }

    -- | The constant type constructor needed for the definition of gmapAccumQl
    newtype CONST c a = CONST { CONST c a -> c
    unCONST :: c }

    -- | The type constructor needed for the definition of gmapAccumQr
    newtype Qr r a = Qr { Qr r a -> r -> r
    unQr  :: r -> r }

    ------------------------------------------------------------------------------
    --
    --      Mapping combinators for twin traversal
    --
    ------------------------------------------------------------------------------

    -- | Twin map for transformation
    gzipWithT :: GenericQ (GenericT) -> GenericQ (GenericT)
    gzipWithT :: GenericQ GenericT -> GenericQ GenericT
    gzipWithT f :: GenericQ GenericT
    f x :: a
    x y :: a
    y = case (forall e. Data e => [GenericT'] -> e -> ([GenericT'], e))
    -> [GenericT'] -> a -> ([GenericT'], a)
    forall d a.
    Data d =>
    (forall e. Data e => a -> e -> (a, e)) -> a -> d -> (a, d)
    gmapAccumT forall e. Data e => [GenericT'] -> e -> ([GenericT'], e)
    perkid [GenericT']
    funs a
    y of
                        ([], c :: a
    c) -> a
    c
                        _       -> [Char] -> a
    forall a. HasCallStack => [Char] -> a
    error "gzipWithT"
     where
      perkid :: [GenericT'] -> b -> ([GenericT'], b)
    perkid a :: [GenericT']
    a d :: b
    d = ([GenericT'] -> [GenericT']
    forall a. [a] -> [a]
    tail [GenericT']
    a, GenericT' -> b -> b
    GenericT' -> GenericT
    unGT ([GenericT'] -> GenericT'
    forall a. [a] -> a
    head [GenericT']
    a) b
    d)
      funs :: [GenericT']
    funs = (forall d. Data d => d -> GenericT') -> a -> [GenericT']
    forall a u. Data a => (forall d. Data d => d -> u) -> a -> [u]
    gmapQ (\k :: d
    k -> GenericT -> GenericT'
    GT (d -> GenericT
    GenericQ GenericT
    f d
    k)) a
    x

    -- | Twin map for monadic transformation
    gzipWithM :: Monad m => GenericQ (GenericM m) -> GenericQ (GenericM m)
    gzipWithM :: GenericQ (GenericM m) -> GenericQ (GenericM m)
    gzipWithM f :: GenericQ (GenericM m)
    f x :: a
    x y :: a
    y = case (forall e. Data e => [GenericM' m] -> e -> ([GenericM' m], m e))
    -> [GenericM' m] -> a -> ([GenericM' m], m a)
    forall d (m :: * -> *) a.
    (Data d, Monad m) =>
    (forall e. Data e => a -> e -> (a, m e)) -> a -> d -> (a, m d)
    gmapAccumM forall e. Data e => [GenericM' m] -> e -> ([GenericM' m], m e)
    forall a (m :: * -> *).
    Data a =>
    [GenericM' m] -> a -> ([GenericM' m], m a)
    perkid [GenericM' m]
    funs a
    y of
                        ([], c :: m a
    c) -> m a
    c
                        _       -> [Char] -> m a
    forall a. HasCallStack => [Char] -> a
    error "gzipWithM"
     where
      perkid :: [GenericM' m] -> a -> ([GenericM' m], m a)
    perkid a :: [GenericM' m]
    a d :: a
    d = ([GenericM' m] -> [GenericM' m]
    forall a. [a] -> [a]
    tail [GenericM' m]
    a, GenericM' m -> a -> m a
    forall (m :: * -> *). GenericM' m -> forall a. Data a => a -> m a
    unGM ([GenericM' m] -> GenericM' m
    forall a. [a] -> a
    head [GenericM' m]
    a) a
    d)
      funs :: [GenericM' m]
    funs = (forall d. Data d => d -> GenericM' m) -> a -> [GenericM' m]
    forall a u. Data a => (forall d. Data d => d -> u) -> a -> [u]
    gmapQ (\k :: d
    k -> GenericM m -> GenericM' m
    forall (m :: * -> *). (forall a. Data a => a -> m a) -> GenericM' m
    GM (d -> GenericM m
    GenericQ (GenericM m)
    f d
    k)) a
    x

    -- | Twin map for queries
    gzipWithQ :: GenericQ (GenericQ r) -> GenericQ (GenericQ [r])
    gzipWithQ :: GenericQ (GenericQ r) -> GenericQ (GenericQ [r])
    gzipWithQ f :: GenericQ (GenericQ r)
    f x :: a
    x y :: a
    y = case (forall e. Data e => [GenericQ' r] -> e -> ([GenericQ' r], r))
    -> [GenericQ' r] -> a -> ([GenericQ' r], [r])
    forall d a q.
    Data d =>
    (forall e. Data e => a -> e -> (a, q)) -> a -> d -> (a, [q])
    gmapAccumQ forall e. Data e => [GenericQ' r] -> e -> ([GenericQ' r], r)
    forall a b. Data a => [GenericQ' b] -> a -> ([GenericQ' b], b)
    perkid [GenericQ' r]
    funs a
    y of
                       ([], r :: [r]
    r) -> [r]
    r
                       _       -> [Char] -> [r]
    forall a. HasCallStack => [Char] -> a
    error "gzipWithQ"
     where
      perkid :: [GenericQ' b] -> a -> ([GenericQ' b], b)
    perkid a :: [GenericQ' b]
    a d :: a
    d = ([GenericQ' b] -> [GenericQ' b]
    forall a. [a] -> [a]
    tail [GenericQ' b]
    a, GenericQ' b -> a -> b
    forall r. GenericQ' r -> forall a. Data a => a -> r
    unGQ ([GenericQ' b] -> GenericQ' b
    forall a. [a] -> a
    head [GenericQ' b]
    a) a
    d)
      funs :: [GenericQ' r]
    funs = (forall d. Data d => d -> GenericQ' r) -> a -> [GenericQ' r]
    forall a u. Data a => (forall d. Data d => d -> u) -> a -> [u]
    gmapQ (\k :: d
    k -> GenericQ r -> GenericQ' r
    forall r. (forall a. Data a => a -> r) -> GenericQ' r
    GQ (d -> GenericQ r
    GenericQ (GenericQ r)
    f d
    k)) a
    x

    ------------------------------------------------------------------------------
    --
    --      Typical twin traversals
    --
    ------------------------------------------------------------------------------

    -- | Generic equality: an alternative to \"deriving Eq\"
    geq :: Data a => a -> a -> Bool

    {-

    Testing for equality of two terms goes like this. Firstly, we
    establish the equality of the two top-level datatype
    constructors. Secondly, we use a twin gmap combinator, namely tgmapQ,
    to compare the two lists of immediate subterms.

    (Note for the experts: the type of the worker geq' is rather general
    but precision is recovered via the restrictive type of the top-level
    operation geq. The imprecision of geq' is caused by the type system's
    unability to express the type equivalence for the corresponding
    couples of immediate subterms from the two given input terms.)

    -}

    geq :: a -> a -> Bool
    geq x0 :: a
    x0 y0 :: a
    y0 = a -> a -> Bool
    GenericQ (GenericQ Bool)
    geq' a
    x0 a
    y0
      where
        geq' :: GenericQ (GenericQ Bool)
        geq' :: a -> GenericQ Bool
    geq' x :: a
    x y :: a
    y =     (a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    x Constr -> Constr -> Bool
    forall a. Eq a => a -> a -> Bool
    == a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    y)
                    Bool -> Bool -> Bool
    && [Bool] -> Bool
    forall (t :: * -> *). Foldable t => t Bool -> Bool
    and (GenericQ (GenericQ Bool) -> a -> a -> [Bool]
    forall r. GenericQ (GenericQ r) -> GenericQ (GenericQ [r])
    gzipWithQ GenericQ (GenericQ Bool)
    geq' a
    x a
    y)

    -- | Generic zip controlled by a function with type-specific branches
    gzip :: GenericQ (GenericM Maybe) -> GenericQ (GenericM Maybe)
    -- See testsuite/.../Generics/gzip.hs for an illustration
    gzip :: GenericQ (GenericM Maybe) -> GenericQ (GenericM Maybe)
    gzip f :: GenericQ (GenericM Maybe)
    f = a -> a -> Maybe a
    GenericQ (GenericM Maybe)
    go
      where
        go :: GenericQ (GenericM Maybe)
        go :: a -> GenericM Maybe
    go x :: a
    x y :: a
    y =
          a -> a -> Maybe a
    GenericQ (GenericM Maybe)
    f a
    x a
    y
          Maybe a -> Maybe a -> Maybe a
    forall a. Maybe a -> Maybe a -> Maybe a
    `orElse`
          if a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    x Constr -> Constr -> Bool
    forall a. Eq a => a -> a -> Bool
    == a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    y
            then GenericQ (GenericM Maybe) -> a -> a -> Maybe a
    forall (m :: * -> *).
    Monad m =>
    GenericQ (GenericM m) -> GenericQ (GenericM m)
    gzipWithM GenericQ (GenericM Maybe)
    go a
    x a
    y
            else Maybe a
    forall a. Maybe a
    Nothing

    -- | Generic comparison: an alternative to \"deriving Ord\"
    gcompare :: Data a => a -> a -> Ordering
    gcompare :: a -> a -> Ordering
    gcompare = a -> a -> Ordering
    forall a b. (Data a, Data b) => a -> b -> Ordering
    gcompare'
      where
        gcompare' :: (Data a, Data b) => a -> b -> Ordering
        gcompare' :: a -> b -> Ordering
    gcompare' x :: a
    x y :: b
    y
          = let repX :: ConstrRep
    repX = Constr -> ConstrRep
    constrRep (Constr -> ConstrRep) -> Constr -> ConstrRep
    forall a b. (a -> b) -> a -> b
    $ a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    x
                repY :: ConstrRep
    repY = Constr -> ConstrRep
    constrRep (Constr -> ConstrRep) -> Constr -> ConstrRep
    forall a b. (a -> b) -> a -> b
    $ b -> Constr
    forall a. Data a => a -> Constr
    toConstr b
    y
            in
            case (ConstrRep
    repX, ConstrRep
    repY) of
              (AlgConstr nX :: ConIndex
    nX,   AlgConstr nY :: ConIndex
    nY)   ->
                ConIndex
    nX ConIndex -> ConIndex -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` ConIndex
    nY Ordering -> Ordering -> Ordering
    forall a. Monoid a => a -> a -> a
    `mappend` [Ordering] -> Ordering
    forall a. Monoid a => [a] -> a
    mconcat (GenericQ (GenericQ Ordering) -> a -> b -> [Ordering]
    forall r. GenericQ (GenericQ r) -> GenericQ (GenericQ [r])
    gzipWithQ GenericQ (GenericQ Ordering)
    forall a b. (Data a, Data b) => a -> b -> Ordering
    gcompare' a
    x b
    y)
              (IntConstr iX :: Integer
    iX,   IntConstr iY :: Integer
    iY)   -> Integer
    iX Integer -> Integer -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Integer
    iY
              (FloatConstr rX :: Rational
    rX, FloatConstr rY :: Rational
    rY) -> Rational
    rX Rational -> Rational -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Rational
    rY
              (CharConstr cX :: Char
    cX,  CharConstr cY :: Char
    cY)  -> Char
    cX Char -> Char -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` Char
    cY
              _ -> [Char] -> Ordering
    forall a. HasCallStack => [Char] -> a
    error "type incompatibility in gcompare"