{-# LANGUAGE TypeFamilies #-} -- | Contains a class and instance for MonadIO implementations that can be run directly in MonadIO and -- | then reconstructed to the original type, without changing the overall semantics. module Control.Monad.IO.Unwrappable (MonadIOWrapType, MonadIOStateType, MonadIOUnwrappable, unwrapState, unwrapMonadIO, rewrapMonadIO) where import Control.Monad.Trans.Class import Control.Monad import Control.Monad.IO.Class import Control.Monad.Error import Control.Monad.Reader import Control.Monad.Reader.Class import Control.Monad.State import Control.Monad.State.Class import Data.IORef data Single a = Single a -- | Represents a MonadIO where any change further up the monad stack can be -- | represented lower down in the stack. class MonadIO m => MonadIOUnwrappable m where type MonadIOWrapType m :: * -> * type MonadIOStateType m :: * -- | Sets up state (e.g. an IORef) to be used to simulate the monad from the -- | IO monad. unwrapState :: m (MonadIOStateType m) -- | Maps the monad to only use IO level constructs and the state set up -- | using unwrapState. unwrapMonadIO :: MonadIOStateType m -> m a -> IO (MonadIOWrapType m a) -- | Reverses a previous unwrapMonadIO operation. rewrapMonadIO :: MonadIOStateType m -> MonadIOWrapType m a -> m a instance MonadIOUnwrappable IO where type MonadIOWrapType IO = Single type MonadIOStateType IO = () unwrapState = return () unwrapMonadIO _ asIO = liftM Single asIO rewrapMonadIO _ (Single x) = return x newtype EitherChain a b c = EitherChain (a (Either b c)) instance (Error e, MonadIO m, MonadIOUnwrappable m) => MonadIOUnwrappable (ErrorT e m) where type MonadIOWrapType (ErrorT e m) = EitherChain (MonadIOWrapType m) e type MonadIOStateType (ErrorT e m) = MonadIOStateType m unwrapState = lift (unwrapState) unwrapMonadIO s m = liftM EitherChain $ unwrapMonadIO s (runErrorT m) rewrapMonadIO s (EitherChain v) = ErrorT (rewrapMonadIO s v) instance (MonadIO m, MonadIOUnwrappable m) => MonadIOUnwrappable (ReaderT r m) where type MonadIOWrapType (ReaderT r m) = MonadIOWrapType m type MonadIOStateType (ReaderT r m) = (r, MonadIOStateType m) unwrapState = liftM2 (,) ask (lift unwrapState) unwrapMonadIO (r, s) m = unwrapMonadIO s (runReaderT m r) rewrapMonadIO (_, s) v = ReaderT (\_ -> rewrapMonadIO s v) instance (MonadIO m, MonadIOUnwrappable m) => MonadIOUnwrappable (StateT r m) where type MonadIOWrapType (StateT r m) = MonadIOWrapType m type MonadIOStateType (StateT r m) = (IORef r, MonadIOStateType m) unwrapState = liftM2 (,) (get >>= (liftIO . newIORef)) (lift unwrapState) unwrapMonadIO (r, s) m = unwrapMonadIO s $ do s0 <- liftIO (readIORef r) (a, v') <- runStateT m s0 liftIO (writeIORef r v') return a rewrapMonadIO (r, s) a = StateT (\_ -> liftM2 (,) (rewrapMonadIO s a) (liftIO . readIORef $ r))