-- |
-- Module: Optics.State
-- Description: 'Setter' utilities for working with 'MonadState'.
--
-- This module contains utilities for working with 'Setter's in a 'MonadState'
-- context.  If you prefer operator versions, you may wish to import
-- "Optics.State.Operators".
--
module Optics.State
  ( modifying
  , modifying'
  , assign
  , assign'
  , use
  , preuse
  ) where

import Control.Monad.State

import Optics.Core

-- | Map over the target(s) of an 'Optic' in our monadic state.
--
-- >>> execState (do modifying _1 (*10); modifying _2 $ stimes 5) (6,"o")
-- (60,"ooooo")
--
-- >>> execState (modifying each $ stimes 2) ("a","b")
-- ("aa","bb")
modifying
  :: (Is k A_Setter, MonadState s m)
  => Optic k is s s a b
  -> (a -> b)
  -> m ()
modifying :: Optic k is s s a b -> (a -> b) -> m ()
modifying Optic k is s s a b
o = (s -> s) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((s -> s) -> m ()) -> ((a -> b) -> s -> s) -> (a -> b) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Optic k is s s a b -> (a -> b) -> s -> s
forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over Optic k is s s a b
o
{-# INLINE modifying #-}

-- | Version of 'modifying' that is strict in both optic application and state
-- modification.
--
-- >>> flip evalState ('a','b') $ modifying _1 (errorWithoutStackTrace "oops")
-- ()
--
-- >>> flip evalState ('a','b') $ modifying' _1 (errorWithoutStackTrace "oops")
-- *** Exception: oops
modifying'
  :: (Is k A_Setter, MonadState s m)
  => Optic k is s s a b
  -> (a -> b)
  -> m ()
modifying' :: Optic k is s s a b -> (a -> b) -> m ()
modifying' Optic k is s s a b
o = (s -> s) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((s -> s) -> m ()) -> ((a -> b) -> s -> s) -> (a -> b) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Optic k is s s a b -> (a -> b) -> s -> s
forall k (is :: IxList) s t a b.
Is k A_Setter =>
Optic k is s t a b -> (a -> b) -> s -> t
over' Optic k is s s a b
o
{-# INLINE modifying' #-}

-- | Replace the target(s) of an 'Optic' in our monadic state with a new value,
-- irrespective of the old.
--
-- >>> execState (do assign _1 'c'; assign _2 'd') ('a','b')
-- ('c','d')
--
-- >>> execState (assign each 'c') ('a','b')
-- ('c','c')
assign
  :: (Is k A_Setter, MonadState s m)
  => Optic k is s s a b
  -> b
  -> m ()
assign :: Optic k is s s a b -> b -> m ()
assign Optic k is s s a b
o = Optic k is s s a b -> (a -> b) -> m ()
forall k s (m :: * -> *) (is :: IxList) a b.
(Is k A_Setter, MonadState s m) =>
Optic k is s s a b -> (a -> b) -> m ()
modifying Optic k is s s a b
o ((a -> b) -> m ()) -> (b -> a -> b) -> b -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> a -> b
forall a b. a -> b -> a
const
{-# INLINE assign #-}

-- | Version of 'assign' that is strict in both optic application and state
-- modification.
--
-- >>> flip evalState ('a','b') $ assign _1 (errorWithoutStackTrace "oops")
-- ()
--
-- >>> flip evalState ('a','b') $ assign' _1 (errorWithoutStackTrace "oops")
-- *** Exception: oops
assign'
  :: (Is k A_Setter, MonadState s m)
  => Optic k is s s a b
  -> b
  -> m ()
assign' :: Optic k is s s a b -> b -> m ()
assign' Optic k is s s a b
o = Optic k is s s a b -> (a -> b) -> m ()
forall k s (m :: * -> *) (is :: IxList) a b.
(Is k A_Setter, MonadState s m) =>
Optic k is s s a b -> (a -> b) -> m ()
modifying' Optic k is s s a b
o ((a -> b) -> m ()) -> (b -> a -> b) -> b -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> a -> b
forall a b. a -> b -> a
const
{-# INLINE assign' #-}

-- | Use the target of a 'Lens', 'Iso', or 'Getter' in the current state.
--
-- >>> evalState (use _1) ('a','b')
-- 'a'
--
-- >>> evalState (use _2) ("hello","world")
-- "world"
--
use
  :: (Is k A_Getter, MonadState s m)
  => Optic' k is s a
  -> m a
use :: Optic' k is s a -> m a
use Optic' k is s a
o = (s -> a) -> m a
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Optic' k is s a -> s -> a
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' k is s a
o)
{-# INLINE use #-}

-- | Use the target of a 'AffineTraveral' or 'AffineFold' in the current state.
--
-- >>> evalState (preuse $ _1 % _Right) (Right 'a','b')
-- Just 'a'
--
-- @since 0.2
preuse
  :: (Is k An_AffineFold, MonadState s m)
  => Optic' k is s a
  -> m (Maybe a)
preuse :: Optic' k is s a -> m (Maybe a)
preuse Optic' k is s a
o = (s -> Maybe a) -> m (Maybe a)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (Optic' k is s a -> s -> Maybe a
forall k (is :: IxList) s a.
Is k An_AffineFold =>
Optic' k is s a -> s -> Maybe a
preview Optic' k is s a
o)
{-# INLINE preuse #-}

-- $setup
-- >>> import Data.Semigroup