module Nes.Internal.MonadState (
    -- * Definition
    MonadState (..),
    modify,
    modify',
    gets,
    getsM,

    -- * Lenses
    (.=),
    (+=),
    (-=),
    (%=),
    use,
    uses,
    usesM,
) where

import qualified Control.Lens as Lens

-- | Very similar to mtl's StateMonad, however we don't use functional dependencies to resolve the type of the state. Monads that have multiple instances for this class will have to use explicit type application
class (Monad m) => MonadState s m where
    get :: m s
    set :: s -> m ()

{-# INLINE modify #-}
modify :: (MonadState s m) => (s -> s) -> m ()
modify :: forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify s -> s
f = m s
forall s (m :: * -> *). MonadState s m => m s
get m s -> (s -> m ()) -> m ()
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= s -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
set (s -> m ()) -> (s -> s) -> s -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. s -> s
f

{-# INLINE modify' #-}
modify' :: (MonadState s m) => (s -> (a, s)) -> m a
modify' :: forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
modify' s -> (a, s)
f = do
    (a
a, s
s) <- (s -> (a, s)) -> m (a, s)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets s -> (a, s)
f
    s -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
set s
s
    a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a

{-# INLINE gets #-}
gets :: (MonadState s m) => (s -> a) -> m a
gets :: forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets s -> a
f = (s -> a) -> m s -> m a
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap s -> a
f m s
forall s (m :: * -> *). MonadState s m => m s
get

{-# INLINE getsM #-}
getsM :: (MonadState s m) => (s -> m a) -> m a
getsM :: forall s (m :: * -> *) a. MonadState s m => (s -> m a) -> m a
getsM s -> m a
f = m s
forall s (m :: * -> *). MonadState s m => m s
get m s -> (s -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= s -> m a
f

(.=) :: (MonadState s m) => Lens.ASetter' s a -> a -> m ()
.= :: forall s (m :: * -> *) a.
MonadState s m =>
ASetter' s a -> a -> m ()
(.=) ASetter' s a
l a
a = (s -> s) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter' s a
l ASetter' s a -> a -> s -> s
forall s t a b. ASetter s t a b -> b -> s -> t
Lens..~ a
a)

(+=) :: (MonadState s m, Num a) => Lens.ASetter' s a -> a -> m ()
+= :: forall s (m :: * -> *) a.
(MonadState s m, Num a) =>
ASetter' s a -> a -> m ()
(+=) ASetter' s a
l a
a = (s -> s) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter' s a
l ASetter' s a -> a -> s -> s
forall a s t. Num a => ASetter s t a a -> a -> s -> t
Lens.+~ a
a)

(-=) :: (MonadState s m, Num a) => Lens.ASetter' s a -> a -> m ()
-= :: forall s (m :: * -> *) a.
(MonadState s m, Num a) =>
ASetter' s a -> a -> m ()
(-=) ASetter' s a
l a
a = (s -> s) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter' s a
l ASetter' s a -> a -> s -> s
forall a s t. Num a => ASetter s t a a -> a -> s -> t
Lens.-~ a
a)

(%=) :: (MonadState s m) => Lens.ASetter' s a -> (a -> a) -> m ()
%= :: forall s (m :: * -> *) a.
MonadState s m =>
ASetter' s a -> (a -> a) -> m ()
(%=) ASetter' s a
l a -> a
f = (s -> s) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter' s a
l ASetter' s a -> (a -> a) -> s -> s
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
Lens.%~ a -> a
f)

use :: (MonadState s m) => Lens.Getting a s a -> m a
use :: forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting a s a
l = (s -> a) -> m a
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Getting a s a -> s -> a
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
Lens.view Getting a s a
l)

uses :: (MonadState s m) => Lens.Getting a s a -> (a -> r) -> m r
uses :: forall s (m :: * -> *) a r.
MonadState s m =>
Getting a s a -> (a -> r) -> m r
uses Getting a s a
l a -> r
f = (s -> r) -> m r
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (a -> r
f (a -> r) -> (s -> a) -> s -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting a s a -> s -> a
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
Lens.view Getting a s a
l)

-- | Like 'uses', but the computation can have side effect
usesM :: (MonadState s m) => Lens.Getting a s a -> (a -> m r) -> m r
usesM :: forall s (m :: * -> *) a r.
MonadState s m =>
Getting a s a -> (a -> m r) -> m r
usesM Getting a s a
l a -> m r
f = (s -> a) -> m a
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Getting a s a -> s -> a
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
Lens.view Getting a s a
l) m a -> (a -> m r) -> m r
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= a -> m r
f