module Control.Monad.Ology.General.Outer where

import Control.Monad.Ology.General.Function
import Import

-- | Monads that can compose as the outer monad with any inner monad to make a monad.
-- See 'Control.Monad.Ology.Specific.ComposeOuter.ComposeOuter'.
-- Instances of this type are isomorphic to @P -> a@ for some type @P@.
--
-- Must satisfy:
--
-- * @fmap (\\ex -> unWExtract ex ma) getExtract = ma@.
class Monad m => MonadOuter m where
    getExtract :: m (WExtract m)

instance MonadOuter Identity where
    getExtract :: Identity (WExtract Identity)
getExtract = forall (m :: Type -> Type) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (m :: Type -> Type). Extract m -> WExtract m
MkWExtract forall a. Identity a -> a
runIdentity

instance MonadOuter ((->) r) where
    getExtract :: r -> WExtract ((->) r)
getExtract r
r = forall (m :: Type -> Type). Extract m -> WExtract m
MkWExtract forall a b. (a -> b) -> a -> b
$ \r -> a
ra -> r -> a
ra r
r

commuteOuter ::
       forall m f a. (MonadOuter m, Functor f)
    => f (m a)
    -> m (f a)
commuteOuter :: forall (m :: Type -> Type) (f :: Type -> Type) a.
(MonadOuter m, Functor f) =>
f (m a) -> m (f a)
commuteOuter f (m a)
fma = do
    MkWExtract Extract m
ext <- forall (m :: Type -> Type). MonadOuter m => m (WExtract m)
getExtract
    forall (m :: Type -> Type) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Extract m
ext f (m a)
fma