module Control.Monad.Classes.ReadState where

import Control.Monad.Classes.Core
import Control.Monad.Classes.Effects
import Control.Monad.Classes.Reader
import Control.Monad.Classes.State
import Control.Monad.Trans.Identity
import Control.Monad.Trans.Class
import Control.Monad.Base
import Control.Monad.Trans.Control
import Data.Peano
import Data.Proxy

-- | 'ReadState' is used to translate reader effects into state effects.
--
-- If you run a computation with 'StateT', this handler is not needed,
-- since 'StateT' already handles read requests.
--
-- This is useful in cases when you work in an abstract 'MonadState' monad
-- and thus have no guarantee that its handler will also accept reader
-- requests.
newtype ReadStateT s m a = ReadStateT (IdentityT m a)
  deriving (Functor, Applicative, Monad, MonadTrans)

runReadState :: Proxy s -> ReadStateT s m a -> m a
runReadState _ (ReadStateT (IdentityT a)) = a

type instance CanDo (ReadStateT s m) eff = ReadStateCanDo s eff

type family ReadStateCanDo s eff where
  ReadStateCanDo s (EffReader s) = True
  ReadStateCanDo s eff = False

instance MonadState s m => MonadReaderN Zero s (ReadStateT s m) where
  askN _ = ReadStateT (IdentityT get)

instance MonadBase b m => MonadBase b (ReadStateT x m) where
  liftBase = lift . liftBase

instance MonadTransControl (ReadStateT x) where
  type StT (ReadStateT x) a = StT IdentityT a
  liftWith = defaultLiftWith ReadStateT (\(ReadStateT a) -> a)
  restoreT = defaultRestoreT ReadStateT

instance MonadBaseControl b m => MonadBaseControl b (ReadStateT s m) where
  type StM (ReadStateT s m) a = StM m a
  liftBaseWith     = defaultLiftBaseWith
  restoreM         = defaultRestoreM