content: -- |
  -- Module: Optics.State.Operators
  -- Description: Infix operators for state-modifying optics.
  --
  -- Defines infix operators for the operations in "Optics.State".  These
  -- operators are not exposed by the main @Optics@ module, but must be imported
  -- explicitly.
  --
  module Optics.State.Operators (
    -- * State modifying optics
    (.=), (?=), (%=),
    -- * State modifying optics with passthrough
    (%%=),
    -- * Returning new value
    (<.=), (<?=), (<%=),
    -- * Returning old value
    (<<.=), (<<?=), (<<%=),
    -- * Passthrough
    PermeableOptic (..),
    ) where
  
  import Control.Monad.State (MonadState)
  import qualified Control.Monad.State as State
  
  import Optics.Core
  import Optics.Passthrough
  import Optics.State
  import Optics.View
  
  infix 4 .=, ?=, %=
  
  -- | Replace the target(s) of an 'Optic' in our monadic state with a new value,
  -- irrespective of the old.
  --
  -- This is an infix version of 'assign'.
  (.=)
    :: (Is k A_Setter, MonadState s m)
    => Optic k is s s a b
    -> b
    -> m ()
  (.=) = assign
  {-# INLINE (.=) #-}
  
  -- | Replace the target(s) of an 'Optic' in our monadic state with 'Just' a new
  -- value, irrespective of the old.
  (?=)
    :: (Is k A_Setter, MonadState s m)
    => Optic k is s s (Maybe a) (Maybe b)
    -> b
    -> m ()
  (?=) = \o -> assign o . Just
  {-# INLINE (?=) #-}
  
  -- | Map over the target(s) of an 'Optic' in our monadic state.
  --
  -- This is an infix version of 'modifying'.
  (%=)
    :: (Is k A_Setter, MonadState s m)
    => Optic k is s s a b
    -> (a -> b)
    -> m ()
  (%=) = modifying
  {-# INLINE (%=) #-}
  
  -------------------------------------------------------------------------------
  -- Extra stuff
  -------------------------------------------------------------------------------
  
  -- | Modify the target of an 'PermeableOptic' in the current state returning
  -- some extra information of type depending on the optic (@r@, @Maybe r@ or
  -- monoidal summary).
  infix 4 %%=
  (%%=)
    :: (PermeableOptic k r, MonadState s m)
    => Optic k is s s a b
    -> (a -> (r, b))
    -> m (ViewResult k r)
  o %%= f = State.state (passthrough o f)
  {-# INLINE (%%=) #-}
  
  -------------------------------------------------------------------------------
  -- Returning new value
  -------------------------------------------------------------------------------
  
  infix 4 <.=, <?=, <%=
  
  -- | Modify the target of a 'PermeableOptic' into your 'Monad''s state by a user
  -- supplied function and return the result.
  (<%=)
    :: (PermeableOptic k b, MonadState s m)
    => Optic k is s s a b
    -> (a -> b)
    -> m (ViewResult k b)
  o <%= f = o %%= \a -> let b = f a in (b, b)
  {-# INLINE (<%=) #-}
  
  -- | Set 'Just' a value with pass-through.
  --
  -- This is useful for chaining assignment without round-tripping through your
  -- 'Monad' stack.
  (<?=)
    :: (PermeableOptic k (Maybe b), MonadState s m)
    => Optic k is s s (Maybe a) (Maybe b)
    -> b
    -> m (ViewResult k (Maybe b))
  o <?= b = o <.= Just b
  {-# INLINE (<?=) #-}
  
  -- | Set with pass-through.
  --
  -- This is useful for chaining assignment without round-tripping through your
  -- 'Monad' stack.
  (<.=)
    :: (PermeableOptic k b, MonadState s m)
    => Optic k is s s a b
    -> b
    -> m (ViewResult k b)
  o <.= b = o <%= const b
  {-# INLINE (<.=) #-}
  
  -------------------------------------------------------------------------------
  -- Returning old value
  -------------------------------------------------------------------------------
  
  infix 4 <<.=, <<?=, <<%=
  
  -- | Modify the target of a 'PermeableOptic' into your 'Monad''s state by a user
  -- supplied function and return the /old/ value that was replaced.
  (<<%=)
    :: (PermeableOptic k a, MonadState s m)
    => Optic k is s s a b
    -> (a -> b)
    -> m (ViewResult k a)
  o <<%= f = o %%= \a -> (a, f a)
  {-# INLINE (<<%=) #-}
  
  -- | Replace the target of a 'PermeableOptic' into your 'Monad''s state with
  -- 'Just' a user supplied value and return the /old/ value that was replaced.
  (<<?=)
    :: (PermeableOptic k (Maybe a), MonadState s m)
    => Optic k is s s (Maybe a) (Maybe b)
    -> b
    -> m (ViewResult k (Maybe a))
  o <<?= b = o <<.= Just b
  {-# INLINE (<<?=) #-}
  
  -- | Replace the target of a 'PermeableOptic' into your 'Monad''s state with a
  -- user supplied value and return the /old/ value that was replaced.
  (<<.=)
    :: (PermeableOptic k a, MonadState s m)
    => Optic k is s s a b
    -> b
    -> m (ViewResult k a)
  o <<.= b = o <<%= const b
  {-# INLINE (<<.=) #-}
  