packages feed

monadology-0.1: src/Control/Monad/Ology/General/Inner.hs

{-# OPTIONS -fno-warn-orphans #-}

module Control.Monad.Ology.General.Inner where

import Control.Monad.Ology.General.Exception.Class
import Control.Monad.Ology.Specific.Result
import Import

-- | Monads that can compose as the inner monad with any outer monad to make a monad.
-- See 'Control.Monad.Ology.Specific.ComposeInner.ComposeInner'.
-- Instances of this type are isomorphic to @Either P (Q,a)@ for some types @P@ and @Q@ (with @Monoid Q@).
--
-- Must satisfy:
--
-- * @retrieveInner (fmap f w) = fmap f (retrieveInner w)@
--
-- * @case retrieveInner w of {Left w' -> fmap absurd w'; Right a -> fmap (\\_ -> a) w;} = w@
class (Traversable m, MonadException m) => MonadInner m where
    retrieveInner :: forall a. m a -> Result (Exc m) a

instance MonadInner Identity where
    retrieveInner (Identity a) = SuccessResult a

instance MonadInner Maybe where
    retrieveInner (Just a) = SuccessResult a
    retrieveInner Nothing = FailureResult ()

instance MonadInner (Either p) where
    retrieveInner (Right b) = SuccessResult b
    retrieveInner (Left a) = FailureResult a

instance Monoid p => MonadInner ((,) p) where
    retrieveInner (_, a) = SuccessResult a

instance MonadInner (Result e) where
    retrieveInner ra = ra

mToMaybe ::
       forall m a. MonadInner m
    => m a
    -> Maybe a
mToMaybe = resultToMaybe . retrieveInner

commuteInner ::
       forall m f a. (MonadInner m, Applicative f)
    => m (f a)
    -> f (m a)
commuteInner mfa =
    case retrieveInner mfa of
        SuccessResult fa -> fmap pure fa
        FailureResult ex -> pure $ throwExc ex