packages feed

flexiwrap-0.0.1: Data/Wrap.hs

{-# OPTIONS_GHC -fglasgow-exts -fallow-undecidable-instances #-}
-- .$Header: c:/Source/Haskell/Wrapper/Data/RCS/Wrap.hs,v 1.1 2010/03/12 23:41:16 dosuser Exp dosuser $
module Data.Wrap (
    Wrapper(..),
    circumpose,
    inCompose, inCompose2,
    inWrapping, inWrapping2,
    traverseWrapping, foldWrapping, foldWrapper,
    inWrapper, inWrapper2,
    asWrapped, asWrapped2,
    Wrap(..),
    InnerWrapT(..), OuterWrapT(..),
    inInnerWrapT, inInnerWrapT2,
    inOuterWrapT, inOuterWrapT2,
    fromInnerWrapT, mFromInnerWrapT, fromOuterWrapT,
    toInnerWrapT, mToInnerWrapT, toOuterWrapT,
    asInnerWrapT, mAsInnerWrapT, asOuterWrapT,
    asInnerWrapT2, mAsInnerWrapT2, asOuterWrapT2,
    -- traverseInnerWrapT, traverseOuterWrapT
    -- traverseWrapT
    traverseWrapper, sequenceWrapper,
    bindWrapper, contWrapper, catchWrapper, fixWrapper,
    readerWrapper, writerWrapper,
    result, argument
) where

import Control.Applicative (Applicative(..), Alternative(..), (<$>))
-- (<$>), liftA2, Alternative(..))
import Control.Compose (Cofunctor(..))
import Control.Monad (MonadPlus(..), liftM)
import Control.Monad.Cont (MonadCont(..))
import Control.Monad.Error (MonadError(..))
import Control.Monad.Fix (MonadFix(..))
import Control.Monad.Reader (MonadReader(..))
import Control.Monad.State(MonadState(..))
import Control.Monad.Trans (MonadTrans(..), MonadIO(..))
import Control.Monad.Writer (MonadWriter(..))
-- lift, 

import Data.Foldable as F (Foldable(..))
-- import Data.Generics (Data, Typeable2(..), mkTyCon, mkTyConApp)
import Data.Monoid (Monoid(..))
import qualified Data.Traversable as T (Traversable(..))

import Test.QuickCheck (Arbitrary(..))

class Wrapper f where
    wrap :: a -> f a
    unwrap :: f a -> a

circumpose :: (c -> d) -> (a -> b) -> (b -> c) -> (a -> d)
circumpose left right = (left .) . (. right)

-- inCompose :: (f b -> b) -> (c -> d) -> (b -> c) -> (f b -> d)
inCompose :: (a -> b) -> (c -> d) -> (b -> c) -> (a -> d)
-- inCompose unwrap wrap = (wrap .) . (. unwrap)
inCompose = flip circumpose

-- inCompose2 :: (a -> b) -> (c -> d) -> (b -> b -> c) -> (a -> a -> d)
inCompose2 :: (forall a. f a -> a) -> (d -> e) ->
    (b -> c -> d) -> (f b -> f c -> e)
inCompose2 unwrap wrap = inCompose unwrap $ inCompose unwrap wrap
-- inCompose2 unwrap wrap = (inCompose unwrap wrap .) . (. unwrap)

inWrapping :: (f a -> a) -> (b -> c) -> (a -> b) -> f a -> c
-- inWrapping unwrap wrap = circumpose wrap unwrap
-- inWrapping = flip circumpose
inWrapping = inCompose

inWrapping2 :: (forall a. f a -> a) -> (d -> e) ->
    (b -> c -> d) -> (f b -> f c -> e)
inWrapping2 unwrap wrap = inWrapping unwrap $ inWrapping unwrap wrap

{-
traverseWrapping :: Functor g => (f a -> a) -> (b -> c) -> (a -> g b) ->
    (f a -> g c)
-}
traverseWrapping :: Functor f => (a -> b) -> (c -> d) ->
    (b -> f c) -> (a -> f d)
traverseWrapping unwrap wrap = inCompose unwrap $ fmap wrap

inWrapper :: Wrapper f => (a -> b) -> f a -> f b
inWrapper = inWrapping unwrap wrap
-- inWrapper = (wrap .) . (. unwrap)

inWrapper2 :: Wrapper f => (a -> b -> c) -> f a -> f b -> f c
inWrapper2 = inWrapping2 unwrap wrap

asWrapped :: (Wrap f a -> Wrap f b) -> (f a -> f b)
asWrapped = inCompose Wrapped unWrapped

asWrapped2 :: (Wrap f a -> Wrap f b -> Wrap f c) -> (f a -> f b -> f c)
asWrapped2 = inCompose Wrapped asWrapped

{-
asWrapped :: Wrapper f => (f a -> f b) -> (a -> b)
asWrapped = inCompose wrap unwrap

asWrapped2 :: Wrapper f => (f a -> f b -> f c) -> (a -> b -> c)
asWrapped2 = inCompose wrap asWrapped
-}

newtype Wrap f a = Wrapped {unWrapped :: f a}
    deriving (Eq, Ord, Monoid)
    -- , Show, Read)
    -- Functor, Applicative, Monad
    -- Foldable, Traversable
    -- Monoid
    -- Arbitrary
    -- Data, Typeable
    -- CoMonad
    -- but NOT
    -- Cofunctor
    -- Alternative, MonadPlus
    -- MonadTrans, MonadState, MonadIO, ...

app_prec = 10

instance Show (f a) => Show (Wrap f a) where
    showsPrec d (Wrapped w) = showParen (d > app_prec) $
        showString "Wrapped " . showsPrec (app_prec+1) w

instance Read (f a) => Read (Wrap f a) where
    readsPrec d r = readParen
        (d > app_prec)
        (\r -> [(Wrapped m, t) |
            ("Wrapped", s) <- lex r,
            (m, t) <- readsPrec (app_prec+1) s
        ])
        r

instance Wrapper f => Wrapper (Wrap f) where
    wrap = Wrapped . wrap
    unwrap = unwrap . unWrapped

instance Wrapper f => Functor (Wrap f) where
    fmap = inWrapper

instance Wrapper f => Applicative (Wrap f) where
    pure = wrap
    (<*>) = inWrapper . unwrap

instance Wrapper f => F.Foldable (Wrap f) where
    foldr f z = flip f z . unwrap

instance Wrapper f => T.Traversable (Wrap f) where
    traverse = traverseWrapping unwrap wrap
    -- traverse = inWrapping unwrap $ fmap wrap
    -- traverse = (fmap wrap .) . (. unwrap)
    sequenceA = fmap wrap . unwrap

instance Wrapper f => Monad (Wrap f) where
    return = wrap
    (>>=) = flip (. unwrap)

instance (Wrapper f, Arbitrary a) => Arbitrary (Wrap f a) where
    arbitrary = wrap <$> arbitrary
    coarbitrary = coarbitrary . unwrap

-- Utility function to construct (>>=) for a target monad <t> from the (>>=)
-- for an implementation monad <i>
-- Parameters:
--   wrap:   function from target monad to implementation monad (t a -> i a)
--   unwrap: vice versa (i a -> t a)
bindWrapper :: (forall a. f a -> g a) -> (d -> e) -> (g a -> (c -> g b) -> d) ->
    f a -> (c -> f b) -> e
bindWrapper wrap unwrap = inCompose wrap $ inCompose (result wrap) unwrap

newtype InnerWrapT f g a = InnerWrapT {runInnerWrapT :: g (Wrap f a)}
    deriving (Eq, Ord, Monoid)
    -- , Show, Read)
    -- deriving (Functor, Applicative, Monad, MonadTrans)
    -- Alternative, MonadPlus
    -- MonadState, MonadIO, ...
    -- Foldable, Traversable
    -- Cofunctor
    -- Monoid
    -- Arbitrary
    -- Data, Typeable
    -- CoMonad

newtype OuterWrapT f g a = OuterWrapT {runOuterWrapT :: Wrap f (g a)}
    deriving (Eq, Ord, Monoid)
    -- , Show, Read)
    -- deriving (Functor, Applicative, Foldable, T.Traversable, Monad,
    -- MonadTrans)
    -- Alternative, MonadPlus
    -- MonadState, MonadIO, ...
    -- Cofunctor, CoMonad
    -- Monoid
    -- Arbitrary
    -- Data, Typeable

inInnerWrapT :: (g (Wrap f a) -> g (Wrap f b)) ->
    InnerWrapT f g a -> InnerWrapT f g b
inInnerWrapT = circumpose InnerWrapT runInnerWrapT

inInnerWrapT2 :: (g (Wrap f a) -> g (Wrap f b) -> g (Wrap f c)) ->
    InnerWrapT f g a -> InnerWrapT f g b -> InnerWrapT f g c
inInnerWrapT2 = circumpose inInnerWrapT runInnerWrapT

inOuterWrapT :: (Wrap f (g a) -> Wrap f (g b)) ->
    OuterWrapT f g a -> OuterWrapT f g b
inOuterWrapT = circumpose OuterWrapT runOuterWrapT

inOuterWrapT2 :: (Wrap f (g a) -> Wrap f (g b) -> Wrap f (g c)) ->
    OuterWrapT f g a -> OuterWrapT f g b -> OuterWrapT f g c
inOuterWrapT2 = circumpose inOuterWrapT runOuterWrapT

fromInnerWrapT :: Functor g => InnerWrapT f g a -> g (f a)
fromInnerWrapT = fmap unWrapped . runInnerWrapT

fromOuterWrapT :: OuterWrapT f g a -> f (g a)
fromOuterWrapT = unWrapped . runOuterWrapT

mFromInnerWrapT :: Monad g => InnerWrapT f g a -> g (f a)
mFromInnerWrapT = liftM unWrapped . runInnerWrapT

toInnerWrapT :: Functor g => g (f a) -> InnerWrapT f g a
toInnerWrapT = InnerWrapT . fmap Wrapped

toOuterWrapT :: f (g a) -> OuterWrapT f g a
toOuterWrapT = OuterWrapT . Wrapped

mToInnerWrapT :: Monad g => g (f a) -> InnerWrapT f g a
mToInnerWrapT = InnerWrapT . liftM Wrapped

asInnerWrapT :: Functor g => (InnerWrapT f g a -> InnerWrapT f g b) ->
    g (f a) -> g (f b)
asInnerWrapT = circumpose fromInnerWrapT toInnerWrapT
-- asInnerWrapT = inCompose (InnerWrapT . fmap Wrapped) fromInnerWrapT

asOuterWrapT :: (OuterWrapT f g a -> OuterWrapT f g b) ->
    f (g a) -> f (g b)
asOuterWrapT = circumpose fromOuterWrapT toOuterWrapT

mAsInnerWrapT :: Monad g => (InnerWrapT f g a -> InnerWrapT f g b) ->
    g (f a) -> g (f b)
mAsInnerWrapT = circumpose mFromInnerWrapT mToInnerWrapT
-- mAsInnerWrapT = inCompose (InnerWrapT . liftM Wrapped) mFromInnerWrapT

asInnerWrapT2 :: Functor g =>
    (InnerWrapT f g a -> InnerWrapT f g b -> InnerWrapT f g c) ->
    g (f a) -> g (f b) -> g (f c)
asInnerWrapT2 = circumpose asInnerWrapT toInnerWrapT

asOuterWrapT2 :: (OuterWrapT f g a -> OuterWrapT f g b -> OuterWrapT f g c) ->
    f (g a) -> f (g b) -> f (g c)
asOuterWrapT2 = circumpose asOuterWrapT toOuterWrapT

mAsInnerWrapT2 :: Monad g =>
    (InnerWrapT f g a -> InnerWrapT f g b -> InnerWrapT f g c) ->
    g (f a) -> g (f b) -> g (f c)
mAsInnerWrapT2 = circumpose mAsInnerWrapT mToInnerWrapT

instance Show (g (Wrap f a)) => Show (InnerWrapT f g a) where
    showsPrec d (InnerWrapT w) = showParen (d > app_prec) $
        showString "InnerWrapT " . showsPrec (app_prec+1) w

instance Read (g (Wrap f a)) => Read (InnerWrapT f g a) where
    readsPrec d r = readParen
        (d > app_prec)
        (\r -> [(InnerWrapT m, t) |
            ("InnerWrapT", s) <- lex r,
            (m, t) <- readsPrec (app_prec+1) s
        ])
        r

instance Show (f (g a)) => Show (OuterWrapT f g a) where
    showsPrec d (OuterWrapT w) = showParen (d > app_prec) $
        showString "OuterWrapT " . showsPrec (app_prec+1) w

instance Read (f (g a)) => Read (OuterWrapT f g a) where
    readsPrec d r = readParen
        (d > app_prec)
        (\r -> [(OuterWrapT m, t) |
            ("OuterWrapT", s) <- lex r,
            (m, t) <- readsPrec (app_prec+1) s
        ])
        r

instance (Wrapper f, Functor g) => Functor (InnerWrapT f g) where
    fmap = inInnerWrapT . fmap . inWrapper

instance (Wrapper f, Functor g) => Functor (OuterWrapT f g) where
    fmap = inOuterWrapT . inWrapper . fmap

instance (Wrapper f, Cofunctor g) => Cofunctor (InnerWrapT f g) where
    -- cofmap h = InnerWrapT . cofmap (fmap h) . runInnerWrapT
    -- cofmap h = inInnerWrapT $ cofmap $ fmap h
    cofmap = inInnerWrapT . cofmap . fmap

-- cofmapCF h (O gf) = O (cofmap (fmap h) gf)

instance (Wrapper f, Cofunctor g) => Cofunctor (OuterWrapT f g) where
    cofmap = inOuterWrapT . fmap . cofmap

-- cofmapFC = inO.fmap.cofmap

instance (Wrapper f, Applicative g) => Applicative (InnerWrapT f g) where
    pure = InnerWrapT . pure . wrap
    (<*>) = inInnerWrapT2 $ (<*>) . fmap (<*>)
    -- (<*>) = inInnerWrapT2 $ inCompose2 (fmap unwrap) (fmap wrap) (<*>)
    {-
    (<*>) :: Wrap f (a -> b) -> Wrap f a -> Wrap f b
    fmap (<*>) :: g (Wrap f (a -> b)) -> g (Wrap f a -> Wrap f b)
    (<*>) . fmap (<*>) :: g (Wrap f (a -> b)) -> g (Wrap f a) -> g (Wrap f b)
    -}

instance (Wrapper f, Applicative g) => Applicative (OuterWrapT f g) where
    pure = OuterWrapT . wrap . pure
    (<*>) = inOuterWrapT2 $ (<*>) . fmap (<*>)
    {-
    (<*>) :: g (a -> b) -> g a -> g b
    fmap (<*>) :: Wrap f (g (a -> b)) -> Wrap f (g a -> g b)
    (<*>) . fmap (<*>) :: Wrap f (g (a -> b)) -> Wrap f (g a) -> Wrap f (g b)
    -}

instance (Wrapper f, Alternative g) => Alternative (InnerWrapT f g) where
    empty = InnerWrapT empty
    (<|>) = inInnerWrapT2 (<|>)

instance (Wrapper f, Alternative g) => Alternative (OuterWrapT f g) where
    empty = OuterWrapT $ wrap empty
    (<|>) = inOuterWrapT2 $ inWrapper2 (<|>)

result = (.)
argument = flip (.)

foldWrapping :: (Foldable f, Foldable g) => (a -> b -> b) -> b -> f (g a) -> b
foldWrapping f z = flip F.foldr z . flip $ F.foldr f

foldWrapper :: (Foldable f, Foldable g) => (c -> f (g a)) ->
    (a -> b -> b) -> b -> c -> b
-- foldWrapper = flip flip foldWrapping $ result . result . argument
foldWrapper = flip (result . result . argument) foldWrapping
-- foldWrapper = result . result . argument `flip` foldWrapping

instance (Wrapper f, Foldable g) => Foldable (InnerWrapT f g) where
    foldr = foldWrapper runInnerWrapT
    -- foldr = (result . result . argument) runInnerWrapT foldWrapping
    -- foldr f z = foldWrapping f z . runInnerWrapT
    -- foldr f z = F.foldr (flip $ F.foldr f) z . runInnerWrapT

instance (Wrapper f, Foldable g) => Foldable (OuterWrapT f g) where
    foldr = foldWrapper runOuterWrapT
    -- foldr = (result . result . argument) runOuterWrapT foldWrapping
    -- foldr f z = foldWrapping f z . runOuterWrapT
    -- foldr f z = F.foldr (flip $ F.foldr f) z . runOuterWrapT

traverseInnerWrapT :: Functor h => (g (Wrap f a) -> h (g' (Wrap f' b))) ->
    InnerWrapT f g a -> h (InnerWrapT f' g' b)
traverseInnerWrapT = traverseWrapping runInnerWrapT InnerWrapT
-- traverseInnerWrapT = (fmap InnerWrapT .) . (. runInnerWrapT)

traverseWrapT :: (T.Traversable t, Applicative f) =>
    ((t a -> f (t b)) -> c) -> (a -> f b) -> c
traverseWrapT wrapper mapper = wrapper $ T.sequenceA . fmap mapper

traverseWrapper :: (T.Traversable t, T.Traversable u, Applicative f) =>
    ((t (u a) -> f (t (u b))) -> c) -> (a -> f b) -> c
traverseWrapper wrapper = traverseWrapT wrapper . T.traverse

sequenceWrapper :: (T.Traversable t, T.Traversable u, Applicative f) =>
    ((t (u (f a)) -> f (t (u a))) -> c) -> c
sequenceWrapper wrapper = traverseWrapT wrapper T.sequenceA

instance (Wrapper f, T.Traversable g) => T.Traversable (InnerWrapT f g) where
    traverse = traverseWrapper traverseInnerWrapT
    -- traverse = traverseWrapT traverseInnerWrapT . T.traverse
    -- traverse f = traverseWrapT traverseInnerWrapT $ T.traverse f
    -- traverse f = traverseInnerWrapT $ T.sequenceA . fmap (T.traverse f)
    {-
    traverse f = fmap InnerWrapT . T.sequenceA .
        fmap (T.traverse f) . runInnerWrapT
    -}
    {-
    InnerWrapT f g a
    -> runInnerWrapT ->
    g (Wrap f a)
    -> fmap (traverse f) ->
    g (h (Wrap f b))
    -> sequenceA ->
    h (g (Wrap f b))
    -> fmap InnerWrapT ->
    h (InnerWrapT f g b)
    -}
    sequenceA = sequenceWrapper traverseInnerWrapT
    -- sequenceA = traverseWrapT traverseInnerWrapT T.sequenceA
    -- sequenceA = traverseInnerWrapT $ T.sequenceA . fmap T.sequenceA
    {-
    sequenceA = fmap InnerWrapT . T.sequenceA .
        fmap T.sequenceA . runInnerWrapT
    -}
    {-
    InnerWrapT f g (h a)
    -> runInnerWrapT ->
    g (Wrap f (h a))
    -> fmap sequenceA ->
    g (h (Wrap f a))
    -> sequenceA ->
    h (g (Wrap f a))
    -> fmap InnerWrapT ->
    h (InnerWrapT f g a)
    -}

traverseOuterWrapT :: Functor h => (Wrap f (g a) -> h (Wrap f' (g' b))) ->
    OuterWrapT f g a -> h (OuterWrapT f' g' b)
traverseOuterWrapT = traverseWrapping runOuterWrapT OuterWrapT
-- traverseOuterWrapT = (fmap OuterWrapT .) . (. runOuterWrapT)

instance (Wrapper f, T.Traversable g) => T.Traversable (OuterWrapT f g) where
    traverse = traverseWrapper traverseOuterWrapT
    {-
    traverse f = fmap OuterWrapT . T.sequenceA .
        fmap (T.traverse f) . runOuterWrapT
    -}
    {-
    OuterWrapT f g a
    -> runOuterWrapT ->
    Wrap f (g a)
    -> fmap (traverse f) ->
    Wrap f (h (g b))
    -> sequenceA ->
    h (Wrap f (g b))
    -> fmap OuterWrapT ->
    h (OuterWrapT f g b)
    -}
    sequenceA = sequenceWrapper traverseOuterWrapT
    {-
    sequenceA = fmap OuterWrapT . T.sequenceA .
        fmap T.sequenceA . runOuterWrapT
    -}
    {-
    OuterWrapT f g (h a)
    -> runOuterWrapT ->
    Wrap f (g (h a))
    -> fmap sequenceA ->
    Wrap f (h (g a))
    -> sequenceA ->
    h (Wrap f (g a))
    -> fmap OuterWrapT ->
    h (OuterWrapT f g a)
    -}

instance (Wrapper f, Monad g) => Monad (InnerWrapT f g) where
    return = InnerWrapT . return . wrap
    a >>= f = InnerWrapT $ runInnerWrapT a >>= runInnerWrapT . f . unwrap

instance (Wrapper f, Monad g) => Monad (OuterWrapT f g) where
    return = OuterWrapT . wrap . return
    a >>= f = OuterWrapT . wrap $
        unwrap (runOuterWrapT a) >>= unwrap . runOuterWrapT . f

instance (Wrapper f, MonadPlus g) => MonadPlus (InnerWrapT f g) where
    mzero = InnerWrapT mzero
    mplus = inInnerWrapT2 mplus

instance (Wrapper f, MonadPlus g) => MonadPlus (OuterWrapT f g) where
    mzero = OuterWrapT $ wrap mzero
    mplus = inOuterWrapT2 $ inWrapper2 mplus

instance Wrapper f => MonadTrans (InnerWrapT f) where
    lift = InnerWrapT . liftM wrap

instance Wrapper f => MonadTrans (OuterWrapT f) where
    lift = OuterWrapT . wrap

instance (Wrapper f, MonadState s g) => MonadState s (InnerWrapT f g) where
    get = lift get
    put = lift . put

instance (Wrapper f, MonadState s g) => MonadState s (OuterWrapT f g) where
    get = lift get
    put = lift . put

instance (Wrapper f, MonadIO g) => MonadIO (InnerWrapT f g) where
    liftIO = lift . liftIO

instance (Wrapper f, MonadIO g) => MonadIO (OuterWrapT f g) where
    liftIO = lift . liftIO

{-
contWrapper :: (b -> d) -> (e -> c) ->
    (((a -> b) -> c) -> b) -> (((a -> d) -> e) -> d)
-}
contWrapper :: (forall b. m b -> n b) -> (n c -> m c) ->
    (((a -> m b) -> m c) -> m d) -> (((a -> n b) -> n c) -> n d)
contWrapper lift unlift = circumpose lift . circumpose unlift $ result lift
{-
contWrapper lift unlift = ((argument $ circumpose unlift (result lift)) .
        result lift
    )
contWrapper lift unlift = ((argument $ inCompose (result lift) unlift) .
        result lift
    )
contWrapper lift unlift = ((argument $
            argument (result lift) . result unlift) .
        result lift
    )
contWrapper lift unlift = ((argument $
            (argument . result) lift . result unlift) .
        result lift
    )
contWrapper lift unlift = ((argument . argument . result) lift .
        (argument . result) unlift .
        result lift
    )
-}

unliftInner :: (Wrapper f, Monad g) => InnerWrapT f g a -> g a
unliftInner = liftM unwrap . runInnerWrapT

innerWrapper :: (Wrapper f, Monad g) => (
        (forall a. g a -> InnerWrapT f g a) ->
        (InnerWrapT f g a -> g a) ->
        b
    ) -> b
innerWrapper w = w lift unliftInner

instance (Wrapper f, MonadCont g) => MonadCont (InnerWrapT f g) where
    callCC = innerWrapper contWrapper callCC
    -- callCC = contWrapper lift unliftInner callCC
    -- callCC = contWrapper lift (liftM unwrap . runInnerWrapT) callCC
    {-
    callCC = ((argument . argument . result) lift .
            (argument . result) (liftM unwrap . runInnerWrapT) .
            result lift
        ) callCC
    -}

unliftOuter :: Wrapper f => OuterWrapT f g a -> g a
unliftOuter = unwrap . runOuterWrapT

outerWrapper :: (Wrapper f, Monad g) => (
        (forall a. g a -> OuterWrapT f g a) ->
        (OuterWrapT f g a -> g a) ->
        b
    ) -> b
outerWrapper w = w lift unliftOuter

instance (Wrapper f, MonadCont g) => MonadCont (OuterWrapT f g) where
    callCC = outerWrapper contWrapper callCC
    -- callCC = contWrapper lift unliftOuter callCC
    -- callCC = contWrapper lift (unwrap . runOuterWrapT) callCC
    {-
    callCC = ((argument . argument . result) lift .
            (argument . result) (unwrap . runOuterWrapT) .
            result lift
        ) callCC
    -}

{-
catchWrapper :: (m a -> n a) -> (n a -> m a) ->
    (m a -> (e -> m a) -> m a) -> (n a -> (e -> n a) -> n a)
-}
catchWrapper :: (a -> b) -> (b -> a) ->
    (a -> (e -> a) -> a) -> (b -> (e -> b) -> b)
catchWrapper lift unlift = inCompose unlift . circumpose lift $ result unlift

instance (Wrapper f, MonadError e g) => MonadError e (InnerWrapT f g) where
    throwError = lift . throwError
    catchError = innerWrapper catchWrapper catchError
    -- catchError = catchWrapper lift unliftInner catchError
    {-
    catchError = (inCompose unliftInner . circumpose lift $ result unliftInner)
        catchError
    -}

instance (Wrapper f, MonadError e g) => MonadError e (OuterWrapT f g) where
    throwError = lift . throwError
    catchError = outerWrapper catchWrapper catchError
    -- catchError = catchWrapper lift unliftOuter catchError
    {-
    catchError = (inCompose unliftOuter . circumpose lift $ result unliftOuter)
        catchError
    -}

fixWrapper :: (m a -> n a) -> (n a -> m a) ->
    ((a -> m a) -> m a) -> ((a -> n a) -> n a)
fixWrapper lift unlift = circumpose lift $ result unlift

instance (Wrapper f, MonadFix g) => MonadFix (InnerWrapT f g) where
    mfix = innerWrapper fixWrapper mfix
    -- mfix = fixWrapper lift unliftInner mfix

instance (Wrapper f, MonadFix g) => MonadFix (OuterWrapT f g) where
    mfix = outerWrapper fixWrapper mfix
    -- mfix = fixWrapper lift unliftOuter mfix

readerWrapper :: (m a -> n a) -> (n a -> m a) ->
    ((r -> r) -> m a -> m a) -> ((r -> r) -> n a -> n a)
readerWrapper lift unlift = result $ inCompose unlift lift

instance (Wrapper f, MonadReader r g) => MonadReader r (InnerWrapT f g) where
    ask = lift ask
    local = innerWrapper readerWrapper local

instance (Wrapper f, MonadReader r g) => MonadReader r (OuterWrapT f g) where
    ask = lift ask
    local = outerWrapper readerWrapper local

writerWrapper :: (m b -> n b) -> (n a -> m a) ->
    (m a -> m b) -> (n a -> n b)
writerWrapper = circumpose

instance (Wrapper f, MonadWriter w g) => MonadWriter w (InnerWrapT f g) where
    tell = lift . tell
    listen = innerWrapper writerWrapper listen
    pass = innerWrapper writerWrapper pass

instance (Wrapper f, MonadWriter w g) => MonadWriter w (OuterWrapT f g) where
    tell = lift . tell
    listen = outerWrapper writerWrapper listen
    pass = outerWrapper writerWrapper pass

instance (Wrapper f, Functor g, Arbitrary (g a)) =>
        Arbitrary (InnerWrapT f g a) where
    arbitrary = InnerWrapT . fmap wrap <$> arbitrary
    coarbitrary = coarbitrary . fmap unwrap . runInnerWrapT

instance (Wrapper f, Arbitrary (g a)) => Arbitrary (OuterWrapT f g a) where
    arbitrary = OuterWrapT . wrap <$> arbitrary
    coarbitrary = coarbitrary . unwrap . runOuterWrapT

-- vim: expandtab:tabstop=4:shiftwidth=4