{-# LANGUAGE UndecidableInstances #-}
module Effectful.Class.State where

import Control.Monad.Trans.Class

import Effectful.Internal.Has
import Effectful.Internal.Monad
import qualified Effectful.State.Dynamic as S

-- | Compatiblity layer for a transition period from MTL-style effect handling
-- to 'Effective.Eff'.
class Monad m => MonadState s m where
  {-# MINIMAL state | get, put #-}

  get :: m s
  get = (s -> (s, s)) -> m s
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
state (\s
s -> (s
s, s
s))

  put :: s -> m ()
  put s
s = (s -> ((), s)) -> m ()
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
state (\s
_ -> ((), s
s))

  state :: (s -> (a, s)) -> m a
  state s -> (a, s)
f = do
    (a
a, s
s) <- s -> (a, s)
f (s -> (a, s)) -> m s -> m (a, s)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m s
forall s (m :: * -> *). MonadState s m => m s
get
    s
s s -> m () -> m ()
`seq` s -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put s
s
    a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a

-- | Generic, overlappable instance.
instance {-# OVERLAPPABLE #-}
  ( MonadState s m
  , MonadTrans t
  , Monad (t m)
  ) => MonadState s (t m) where
  get :: t m s
get   = m s -> t m s
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m s
forall s (m :: * -> *). MonadState s m => m s
get
  put :: s -> t m ()
put   = m () -> t m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> t m ()) -> (s -> m ()) -> s -> t m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. s -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put
  state :: (s -> (a, s)) -> t m a
state = m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> t m a) -> ((s -> (a, s)) -> m a) -> (s -> (a, s)) -> t m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (s -> (a, s)) -> m a
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
state

instance S.State s :> es => MonadState s (Eff es) where
  get :: Eff es s
get   = Eff es s
forall s (es :: [*]). (State s :> es) => Eff es s
S.get
  put :: s -> Eff es ()
put   = s -> Eff es ()
forall s (es :: [*]). (State s :> es) => s -> Eff es ()
S.put
  state :: (s -> (a, s)) -> Eff es a
state = (s -> (a, s)) -> Eff es a
forall s (es :: [*]) a.
(State s :> es) =>
(s -> (a, s)) -> Eff es a
S.state

modify :: MonadState s m => (s -> s) -> m ()
modify :: (s -> s) -> m ()
modify s -> s
f = (s -> ((), s)) -> m ()
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
state (\s
s -> ((), s -> s
f s
s))