{-# LANGUAGE UndecidableInstances #-}
module Effectful.Class.Reader
  ( MonadReader(..)
  , asks
  ) where

import Control.Monad.Trans.Class
import Control.Monad.Trans.Control

import Effectful.Internal.Has
import Effectful.Internal.Monad
import qualified Effectful.Reader as R

-- | Compatiblity layer for a transition period from MTL-style effect handling
-- to 'Effective.Eff'.
class Monad m => MonadReader r m where
  {-# MINIMAL (ask | reader), local #-}
  ask :: m r
  ask = reader id

  local :: (r -> r) -> m a -> m a

  reader :: (r -> a) -> m a
  reader f = ask >>= pure . f

-- | Generic, overlappable instance.
instance {-# OVERLAPPABLE #-}
  ( MonadReader r m
  , MonadTransControl t
  , Monad (t m)
  ) => MonadReader r (t m) where
  ask       = lift ask
  local f m = liftWith (\run -> local f (run m)) >>= restoreT . pure
  reader    = lift . reader

instance R.Reader r :> es => MonadReader r (Eff es) where
  ask    = R.ask
  local  = R.local
  reader = R.reader

asks :: MonadReader r m => (r -> a) -> m a
asks = reader