{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
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)
newtype AppT env m a = AppT { unAppT :: ReaderT env m a }
deriving (Functor, Applicative, Monad, MonadTrans, MonadReader env, MonadIO, MonadThrow, MonadCatch, MonadMask)
type App env = AppT env IO
runAppT :: env -> AppT env m a -> m a
runAppT env ma = runReaderT (unAppT ma) env
{-# INLINE runAppT #-}
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)