content: {-# LANGUAGE ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, ExistentialQuantification, Rank2Types #-}
  {-# OPTIONS_GHC -Wno-orphans #-}
  
  {- |
      /DEPRECATED/: Use "Data.Generics.Uniplate.Data" instead.
  
      This module exports 'Biplate' instances for everything with 'Data' defined.
      Using GHC the 'Data' instances can be constructed with @deriving Data@.
  -}
  module Data.Generics.PlateData
      {-# DEPRECATED "Use Data.Generics.Uniplate.Data instead" #-}
      (
      module Data.Generics.Biplate
      ) where
  
  import Data.Generics.Biplate
  import Data.Generics.Uniplate.Internal.Utils
  import Data.Generics
  
  
  data Box find = Box {fromBox :: forall a . Typeable a => a -> Answer find}
  
  data Answer a = Hit {_fromHit :: a} -- you just hit the element you were after (here is a cast)
                | Follow -- go forward, you will find something
                | Miss -- you failed to sink my battleship!
  
  
  
  containsMatch :: (Data start, Typeable start, Data find, Typeable find) =>
                   start -> find ->
                   Box find
  
  -- GHC 6.4.2 does not export typeRepKey, so we can't do the trick
  -- as efficiently, so we just give up and revert to always following
  
  containsMatch start find = Box query
      where
          query a = case cast a of
                         Just y -> Hit y
                         Nothing -> Follow
  
  
  instance (Data a, Typeable a) => Uniplate a where
      uniplate = collect_generate (fromBox answer)
          where
              answer :: Box a
              answer = containsMatch (undefined :: a) (undefined :: a)
  
  
  instance (Data a, Data b, Uniplate b, Typeable a, Typeable b) => Biplate a b where
      biplate = collect_generate_self (fromBox answer)
          where
              answer :: Box b
              answer = containsMatch (undefined :: a) (undefined :: b)
  
  
  newtype C x a = C {fromC :: CC x a}
  
  type CC x a = (Str x, Str x -> a)
  
  
  collect_generate_self :: (Data on, Data with, Typeable on, Typeable with) =>
                           (forall a . Typeable a => a -> Answer with) -> on -> CC with on
  collect_generate_self oracle x = res
          where
              res = case oracle x of
                         Hit y -> (One y, \(One x) -> unsafeCoerce x)
                         Follow -> collect_generate oracle x
                         Miss -> (Zero, \_ -> x)
  
  
  collect_generate :: (Data on, Data with, Typeable on, Typeable with) =>
                      (forall a . Typeable a => a -> Answer with) -> on -> CC with on
  collect_generate oracle item = fromC $ gfoldl combine create item
      where
          -- forall a b . Data a => C with (a -> b) -> a -> C with b
          combine (C (c,g)) x = case collect_generate_self oracle x of
                                    (c2, g2) -> C (Two c c2, \(Two c' c2') -> g c' (g2 c2'))
  
          -- forall g . g -> C with g
          create x = C (Zero, \_ -> x)
  