content: -- | 'Proxied' monad. @'Proxied' x@ is a monad transformer that has a global
  -- configuration parameter of type @x@ associated with it.
  --
  -- It is used to implement things like @ZoomT@\/@runZoom@ and
  -- @CustromWriterT@\/@evalWriterWith@.
  --
  -- Most of the time you don't need to use this directly. It is exported for two purposes:
  --
  -- * you can use it to define new monad transformers
  --
  -- * you can define instances for @'Proxied' x@ and transformers that are
  -- based on it
  module Control.Monad.Classes.Proxied
    ( module Control.Monad.Classes.Proxied
    , R.Reifies
    , Proxy#
    , proxy#
    )
    where
  
  import Control.Applicative
  import Control.Monad
  import Control.Monad.Base
  import Control.Monad.IO.Class
  import Control.Monad.Trans.Control
  import Control.Monad.Trans.Class
  import GHC.Prim (Proxy#, proxy#)
  import qualified Data.Reflection as R
  import Data.Proxy
  
  newtype Proxied x m a = Proxied (forall (q :: *). R.Reifies q x => Proxy# q -> m a)
  
  instance Functor m => Functor (Proxied x m) where
    fmap f (Proxied g) = Proxied (\px -> fmap f (g px))
  
  instance Applicative m => Applicative (Proxied x m) where
    pure x = Proxied (\_ -> pure x)
    Proxied a <*> Proxied b = Proxied (\px -> a px <*> b px)
  
  instance Monad m => Monad (Proxied x m) where
    return x = Proxied (\_ -> return x)
    Proxied a >>= k = Proxied $ \px ->
      a px >>= \v ->
      case k v of
        Proxied b -> b px
  
  instance Alternative m => Alternative (Proxied x m) where
    empty = Proxied $ \_ -> empty
    Proxied a <|> Proxied b = Proxied (\px -> a px <|> b px)
  
  instance MonadPlus m => MonadPlus (Proxied x m) where
    mzero = Proxied $ \_ -> mzero
    Proxied a `mplus` Proxied b = Proxied (\px -> a px `mplus` b px)
  
  instance MonadTrans (Proxied x) where
    lift a = Proxied $ \_ -> a
  
  instance MonadIO m => MonadIO (Proxied x m) where
    liftIO = lift . liftIO
  
  instance MonadBase b m => MonadBase b (Proxied x m) where
    liftBase = liftBaseDefault
  
  instance MonadTransControl (Proxied x) where
    type StT (Proxied x) a = a
    liftWith f = Proxied $ \px -> f $ \(Proxied a) -> a px
    restoreT a = Proxied $ \_ -> a
  
  fromProxy# :: Proxy# a -> Proxy a
  fromProxy# _ = Proxy
  
  toProxy# :: Proxy a -> Proxy# a
  toProxy# _ = proxy#
  
  reify :: a -> (forall (q :: *). R.Reifies q a => Proxy# q -> r) -> r
  reify a k = R.reify a $ \px -> k (toProxy# px)
  
  reflect :: R.Reifies q a => Proxy# q -> a
  reflect px = R.reflect (fromProxy# px)
  