-- | MonadState without the function dependency @m -> s@.
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Language.Haskell.TH.TypeGraph.HasState
    ( HasState(getState, modifyState)
    ) where

import Control.Monad.Reader (ReaderT)
import Control.Monad.RWS (RWST)
import Control.Monad.State (StateT, get, modify)
import Control.Monad.Trans (lift)
import Control.Monad.Writer (WriterT)

-- | This class allows you to access bits of the State by type,
-- without knowing exactly what the overall state type is.  For
-- example:
--
--   typeGraphEdges :: (DsMonad m,
--                      MonadReader TypeGraph m,
--                      HasState (Set TGV) m,
--                      HasState (Map Type (E Type)) m) => ...
--
-- This will work as long as the two HasState instances exist for
-- whatever the actual State type is.  It still can't reach down
-- into nested StateT monads, you may need to use lift for that.

class HasState s m where
    getState :: m s
    modifyState :: (s -> s) -> m ()

instance Monad m => HasState s (StateT s m) where
    getState = get
    modifyState = modify

instance (Monad m, Monoid w) => HasState s (RWST r w s m) where
    getState = get
    modifyState = modify

instance (Monad m, HasState s m) => HasState s (ReaderT r m) where
    getState = lift getState
    modifyState f = lift $ modifyState f

instance (Monad m, Monoid w, HasState s m) => HasState s (WriterT w m) where
    getState = lift getState
    modifyState f = lift $ modifyState f