{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
-- | Labelled 'State' operations.
--
-- @since 1.0.2.0
module Control.Effect.State.Labelled
( -- * State effect
  State
, get
, gets
, put
, modify
, modifyLazy
, state
  -- * Re-exports
, Algebra
, Has
, HasLabelled
, run
) where

import           Control.Effect.Labelled
import qualified Control.Effect.State as S
import           Control.Effect.State.Internal

-- | Get the current state value.
--
-- @
-- runState a ('runLabelled' @label ('get' @label) '>>=' k) = runState a (k a)
-- @
--
-- @since 1.0.2.0
get :: forall label s m sig . HasLabelled label (State s) sig m => m s
get :: forall {k} (label :: k) s (m :: * -> *)
       (sig :: (* -> *) -> * -> *).
HasLabelled label (State s) sig m =>
m s
get = forall (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *) a.
UnderLabel label sub m a -> m a
forall {k} (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *)
       a.
UnderLabel label sub m a -> m a
runUnderLabel @label UnderLabel label (State s) m s
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State s) sig m =>
m s
S.get
{-# INLINEABLE get #-}

-- | Project a function out of the current state value.
--
-- @
-- 'gets' f = 'fmap' f 'get'
-- @
--
-- @since 1.0.2.0
gets :: forall label s m a sig . HasLabelled label (State s) sig m => (s -> a) -> m a
gets :: forall {k} (label :: k) s (m :: * -> *) a
       (sig :: (* -> *) -> * -> *).
HasLabelled label (State s) sig m =>
(s -> a) -> m a
gets s -> a
f = forall (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *) a.
UnderLabel label sub m a -> m a
forall {k} (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *)
       a.
UnderLabel label sub m a -> m a
runUnderLabel @label ((s -> a) -> UnderLabel label (State s) m a
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *) a.
Has (State s) sig m =>
(s -> a) -> m a
S.gets s -> a
f)
{-# INLINEABLE gets #-}

-- | Replace the state value with a new value.
--
-- @
-- runState a ('runLabelled' @label ('put' @label b) '>>' m) = runState b m
-- @
--
-- @since 1.0.2.0
put :: forall label s m sig . HasLabelled label (State s) sig m => s -> m ()
put :: forall {k} (label :: k) s (m :: * -> *)
       (sig :: (* -> *) -> * -> *).
HasLabelled label (State s) sig m =>
s -> m ()
put s
s = forall (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *) a.
UnderLabel label sub m a -> m a
forall {k} (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *)
       a.
UnderLabel label sub m a -> m a
runUnderLabel @label (s -> UnderLabel label (State s) m ()
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State s) sig m =>
s -> m ()
S.put s
s)
{-# INLINEABLE put #-}

-- | Replace the state value with the result of applying a function to the current state value.
--   This is strict in the new state.
--
-- @
-- 'modify' f = 'get' '>>=' ('put' . f '$!')
-- @
--
-- @since 1.0.2.0
modify :: forall label s m sig . HasLabelled label (State s) sig m => (s -> s) -> m ()
modify :: forall {k} (label :: k) s (m :: * -> *)
       (sig :: (* -> *) -> * -> *).
HasLabelled label (State s) sig m =>
(s -> s) -> m ()
modify s -> s
f = forall (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *) a.
UnderLabel label sub m a -> m a
forall {k} (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *)
       a.
UnderLabel label sub m a -> m a
runUnderLabel @label ((s -> s) -> UnderLabel label (State s) m ()
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State s) sig m =>
(s -> s) -> m ()
S.modify s -> s
f)
{-# INLINEABLE modify #-}

-- | Replace the state value with the result of applying a function to the current state value.
--   This is lazy in the new state; injudicious use of this function may lead to space leaks.
--
-- @
-- 'modifyLazy' f = 'get' '>>=' 'put' . f
-- @
--
-- @since 1.0.2.0
modifyLazy :: forall label s m sig . HasLabelled label (State s) sig m => (s -> s) -> m ()
modifyLazy :: forall {k} (label :: k) s (m :: * -> *)
       (sig :: (* -> *) -> * -> *).
HasLabelled label (State s) sig m =>
(s -> s) -> m ()
modifyLazy s -> s
f = forall (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *) a.
UnderLabel label sub m a -> m a
forall {k} (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *)
       a.
UnderLabel label sub m a -> m a
runUnderLabel @label ((s -> s) -> UnderLabel label (State s) m ()
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State s) sig m =>
(s -> s) -> m ()
S.modifyLazy s -> s
f)
{-# INLINEABLE modifyLazy #-}

-- | Compute a new state and a value in a single step.
--
-- @
-- 'state' f = 'gets' f '>>=' \\ (s, a) -> 'put' s '>>' 'pure' a
-- @
--
-- @since 1.0.2.0
state :: forall label s m a sig . HasLabelled label (State s) sig m => (s -> (s, a)) -> m a
state :: forall {k} (label :: k) s (m :: * -> *) a
       (sig :: (* -> *) -> * -> *).
HasLabelled label (State s) sig m =>
(s -> (s, a)) -> m a
state s -> (s, a)
f = forall (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *) a.
UnderLabel label sub m a -> m a
forall {k} (label :: k) (sub :: (* -> *) -> * -> *) (m :: * -> *)
       a.
UnderLabel label sub m a -> m a
runUnderLabel @label ((s -> (s, a)) -> UnderLabel label (State s) m a
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *) a.
Has (State s) sig m =>
(s -> (s, a)) -> m a
S.state s -> (s, a)
f)
{-# INLINEABLE state #-}