{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | -- Module: Boots.App.Internal -- Copyright: 2019 Daniel YU -- License: BSD3 -- Maintainer: leptonyu@gmail.com -- Stability: experimental -- Portability: portable -- -- This module defines a generic application monad transformation. -- module Boots.App.Internal( AppT , App , runAppT , withAppT , MonadReader(..) , asks ) where import Control.Monad.Catch import Control.Monad.IO.Unlift import Control.Monad.Reader import Unsafe.Coerce (unsafeCoerce) -- | Application monad transformation. newtype AppT env m a = AppT { unAppT :: ReaderT env m a } deriving (Functor, Applicative, Monad, MonadTrans, MonadReader env, MonadIO, MonadThrow, MonadCatch, MonadMask) -- | Simple IO monad. type App env = AppT env IO -- | Run application monad transformation. runAppT :: env -> AppT env m a -> m a runAppT env ma = runReaderT (unAppT ma) env {-# INLINE runAppT #-} -- | Execute a computation in a modified environment. withAppT :: (env -> env) -> AppT env m a -> AppT env m a withAppT = unsafeCoerce withReaderT {-# INLINE withAppT #-} instance MonadUnliftIO m => MonadUnliftIO (AppT env m) where {-# INLINE askUnliftIO #-} askUnliftIO = AppT $ ReaderT $ \r -> withUnliftIO $ \u -> return (UnliftIO (unliftIO u . runAppT r)) {-# INLINE withRunInIO #-} withRunInIO inner = AppT $ ReaderT $ \r -> withRunInIO $ \run -> inner (run . runAppT r)