-- | Lenses allow you to use fields of the state of a state monad as if they were variables in an imperative language.
-- 'use' is used to retrieve the value of a variable, and '.=' and '%=' allow you to set and modify a variable.
-- C-style compound assignments are also provided.
module Lens.Family.State.Strict
  ( zoom
  , use, uses
  , (%=)
  , assign, (.=)
  , (%%=)
  , (<~)
-- * Compound Assignments
  , (+=), (-=), (*=)
  , (//=)
  , (&&=), (||=)
  , (<>=)
-- * Strict Assignments
  , (%!=)
  , (+!=), (-!=), (*!=)
  , (//!=)
  , (&&!=), (||!=)
  , (<>!=)
-- * Types
  , Zooming
-- * Re-exports
  , LensLike, LensLike'
  , FoldLike, Constant
  , ASetter, ASetter', Identity
  , StateT, Writer
  ) where

import Control.Monad (liftM)
import Control.Monad.Trans.State.Strict (StateT(..), state, get, modify, modify')
import Control.Monad.Trans.Writer.Lazy (Writer, writer, runWriter)
import Data.Tuple (swap)
import Lens.Family
import Lens.Family.State.Zoom

{- all these Monad constraints could be weakened to Functor or Applicative constraints -}

zoom :: Monad m => LensLike' (Zooming m c) s a -> StateT a m c -> StateT s m c
-- ^ @
-- zoom :: Monad m => Lens' s a -> StateT a m c -> StateT s m c
-- @
--
-- Lift a stateful operation on a field to a stateful operation on the whole state.
-- This is a good way to call a \"subroutine\" that only needs access to part of the state.
--
-- @
-- zoom :: (Monad m, Monoid c) => Traversal' s a -> StateT a m c -> StateT s m c
-- @
--
-- Run the \"subroutine\" on each element of the traversal in turn and 'mconcat' all the results together.
--
-- @
-- zoom :: Monad m => Traversal' s a -> StateT a m () -> StateT s m ()
-- @
--
-- Run the \"subroutine\" on each element the traversal in turn.
zoom :: LensLike' (Zooming m c) s a -> StateT a m c -> StateT s m c
zoom LensLike' (Zooming m c) s a
l StateT a m c
m = (s -> m (c, s)) -> StateT s m c
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
StateT ((s -> m (c, s)) -> StateT s m c)
-> (s -> m (c, s)) -> StateT s m c
forall a b. (a -> b) -> a -> b
$ Zooming m c s -> m (c, s)
forall (m :: * -> *) c a. Zooming m c a -> m (c, a)
unZooming (Zooming m c s -> m (c, s))
-> (s -> Zooming m c s) -> s -> m (c, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LensLike' (Zooming m c) s a
l (m (c, a) -> Zooming m c a
forall (m :: * -> *) c a. m (c, a) -> Zooming m c a
Zooming (m (c, a) -> Zooming m c a)
-> (a -> m (c, a)) -> a -> Zooming m c a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StateT a m c -> a -> m (c, a)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT StateT a m c
m))

use :: Monad m => FoldLike a s t a b -> StateT s m a
-- ^ @
-- use :: Monad m => Getter s t a b -> StateT s m a
-- @
--
-- Retrieve a field of the state
--
-- @
-- use :: (Monad m, Monoid a) => Fold s t a b -> StateT s m a
-- @
--
-- Retrieve a monoidal summary of all the referenced fields from the state
use :: FoldLike a s t a b -> StateT s m a
use FoldLike a s t a b
l = FoldLike a s t a b -> s -> a
forall a s t b. FoldLike a s t a b -> s -> a
view FoldLike a s t a b
l (s -> a) -> StateT s m s -> StateT s m a
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` StateT s m s
forall (m :: * -> *) s. Monad m => StateT s m s
get

uses :: Monad m => FoldLike r s t a b -> (a -> r) -> StateT s m r
-- ^ @
-- uses :: (Monad m, Monoid r) => Fold s t a b -> (a -> r) -> StateT s m r
-- @
--
-- Retrieve all the referenced fields from the state and foldMap the results together with @f :: a -> r@.
--
-- @
-- uses :: Monad m => Getter s t a b -> (a -> r) -> StateT s m r
-- @
--
-- Retrieve a field of the state and pass it through the function @f :: a -> r@.
--
-- @uses l f = f \<$> use l@
uses :: FoldLike r s t a b -> (a -> r) -> StateT s m r
uses FoldLike r s t a b
l a -> r
f = FoldLike r s t a b -> (a -> r) -> s -> r
forall r s t a b. FoldLike r s t a b -> (a -> r) -> s -> r
views FoldLike r s t a b
l a -> r
f (s -> r) -> StateT s m s -> StateT s m r
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` StateT s m s
forall (m :: * -> *) s. Monad m => StateT s m s
get

infix 4 %=

-- | Modify a field of the state.
(%=) :: Monad m => ASetter s s a b -> (a -> b) -> StateT s m ()
ASetter s s a b
l %= :: ASetter s s a b -> (a -> b) -> StateT s m ()
%= a -> b
f = (s -> s) -> StateT s m ()
forall (m :: * -> *) s. Monad m => (s -> s) -> StateT s m ()
modify (ASetter s s a b
l ASetter s s a b -> (a -> b) -> s -> s
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ a -> b
f)

infix 4 .=

-- | Set a field of the state.
(.=) :: Monad m => ASetter s s a b -> b -> StateT s m ()
ASetter s s a b
l .= :: ASetter s s a b -> b -> StateT s m ()
.= b
v = ASetter s s a b
l ASetter s s a b -> (a -> b) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= b -> a -> b
forall a b. a -> b -> a
const b
v

-- | Set a field of the state.
assign :: Monad m => ASetter s s a b -> b -> StateT s m ()
assign :: ASetter s s a b -> b -> StateT s m ()
assign = ASetter s s a b -> b -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> b -> StateT s m ()
(.=)

infixr 2 <~

-- | Set a field of the state using the result of executing a stateful command.
(<~) :: Monad m => ASetter s s a b -> StateT s m b -> StateT s m ()
ASetter s s a b
l <~ :: ASetter s s a b -> StateT s m b -> StateT s m ()
<~ StateT s m b
v = ASetter s s a b -> b -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> b -> StateT s m ()
assign ASetter s s a b
l (b -> StateT s m ()) -> StateT s m b -> StateT s m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< StateT s m b
v

infix 4 %%=

(%%=) :: Monad m => LensLike (Writer c) s s a b -> (a -> (c, b)) -> StateT s m c
-- ^ @
-- (%%=) :: Monad m => Lens s s a b -> (a -> (c, b)) -> StateT s m c
-- @
--
-- Modify a field of the state while returning another value.
--
-- @
-- (%%=) :: (Monad m, Monoid c) => Traversal s s a b -> (a -> (c, b)) -> StateT s m c
-- @
--
-- Modify each field of the state and return the 'mconcat' of the other values.
LensLike (Writer c) s s a b
l %%= :: LensLike (Writer c) s s a b -> (a -> (c, b)) -> StateT s m c
%%= a -> (c, b)
f = (s -> (c, s)) -> StateT s m c
forall (m :: * -> *) s a. Monad m => (s -> (a, s)) -> StateT s m a
state ((s, c) -> (c, s)
forall a b. (a, b) -> (b, a)
swap ((s, c) -> (c, s)) -> (s -> (s, c)) -> s -> (c, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Writer c s -> (s, c)
forall w a. Writer w a -> (a, w)
runWriter (Writer c s -> (s, c)) -> (s -> Writer c s) -> s -> (s, c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LensLike (Writer c) s s a b
l ((b, c) -> WriterT c Identity b
forall (m :: * -> *) a w. Monad m => (a, w) -> WriterT w m a
writer ((b, c) -> WriterT c Identity b)
-> (a -> (b, c)) -> a -> WriterT c Identity b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (c, b) -> (b, c)
forall a b. (a, b) -> (b, a)
swap ((c, b) -> (b, c)) -> (a -> (c, b)) -> a -> (b, c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> (c, b)
f))

infixr 4 +=, -=, *=

(+=), (-=), (*=) :: (Monad m, Num a) => ASetter' s a -> a -> StateT s m ()
ASetter' s a
l += :: ASetter' s a -> a -> StateT s m ()
+= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= (a -> a -> a
forall a. Num a => a -> a -> a
+ a
a)
ASetter' s a
l -= :: ASetter' s a -> a -> StateT s m ()
-= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= a -> a -> a
forall a. Num a => a -> a -> a
subtract a
a
ASetter' s a
l *= :: ASetter' s a -> a -> StateT s m ()
*= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= (a -> a -> a
forall a. Num a => a -> a -> a
* a
a)

infixr 4 //=

(//=) :: (Monad m, Fractional a) => ASetter' s a -> a -> StateT s m ()
ASetter' s a
l //= :: ASetter' s a -> a -> StateT s m ()
//= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= (a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
a)

infixr 4 &&=, ||=

(&&=), (||=) :: Monad m => ASetter' s Bool -> Bool -> StateT s m ()
ASetter' s Bool
l &&= :: ASetter' s Bool -> Bool -> StateT s m ()
&&= Bool
a = ASetter' s Bool
l ASetter' s Bool -> (Bool -> Bool) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= (Bool -> Bool -> Bool
&& Bool
a)
ASetter' s Bool
l ||= :: ASetter' s Bool -> Bool -> StateT s m ()
||= Bool
a = ASetter' s Bool
l ASetter' s Bool -> (Bool -> Bool) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= (Bool -> Bool -> Bool
|| Bool
a)

infixr 4 <>=

-- | Monoidally append a value to all referenced fields of the state.
(<>=) :: (Monad m, Monoid a) => ASetter' s a -> a -> StateT s m ()
ASetter' s a
l <>= :: ASetter' s a -> a -> StateT s m ()
<>= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%= (a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
a)

infix 4 %!=

-- | Strictly modify a field of the state.
(%!=) :: Monad m => ASetter s s a b -> (a -> b) -> StateT s m ()
ASetter s s a b
l %!= :: ASetter s s a b -> (a -> b) -> StateT s m ()
%!= a -> b
f = (s -> s) -> StateT s m ()
forall (m :: * -> *) s. Monad m => (s -> s) -> StateT s m ()
modify' (ASetter s s a b
l ASetter s s a b -> (a -> b) -> s -> s
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ a -> b
f)

infixr 4 +!=, -!=, *!=

(+!=), (-!=), (*!=) :: (Monad m, Num a) => ASetter' s a -> a -> StateT s m ()
ASetter' s a
l +!= :: ASetter' s a -> a -> StateT s m ()
+!= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= (a -> a -> a
forall a. Num a => a -> a -> a
+ a
a)
ASetter' s a
l -!= :: ASetter' s a -> a -> StateT s m ()
-!= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= a -> a -> a
forall a. Num a => a -> a -> a
subtract a
a
ASetter' s a
l *!= :: ASetter' s a -> a -> StateT s m ()
*!= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= (a -> a -> a
forall a. Num a => a -> a -> a
* a
a)

infixr 4 //!=

(//!=) :: (Monad m, Fractional a) => ASetter' s a -> a -> StateT s m ()
ASetter' s a
l //!= :: ASetter' s a -> a -> StateT s m ()
//!= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= (a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
a)

infixr 4 &&!=, ||!=

(&&!=), (||!=) :: Monad m => ASetter' s Bool -> Bool -> StateT s m ()
ASetter' s Bool
l &&!= :: ASetter' s Bool -> Bool -> StateT s m ()
&&!= Bool
a = ASetter' s Bool
l ASetter' s Bool -> (Bool -> Bool) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= (Bool -> Bool -> Bool
&& Bool
a)
ASetter' s Bool
l ||!= :: ASetter' s Bool -> Bool -> StateT s m ()
||!= Bool
a = ASetter' s Bool
l ASetter' s Bool -> (Bool -> Bool) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= (Bool -> Bool -> Bool
|| Bool
a)

infixr 4 <>!=

(<>!=) :: (Monad m, Monoid a) => ASetter' s a -> a -> StateT s m ()
ASetter' s a
l <>!= :: ASetter' s a -> a -> StateT s m ()
<>!= a
a = ASetter' s a
l ASetter' s a -> (a -> a) -> StateT s m ()
forall (m :: * -> *) s a b.
Monad m =>
ASetter s s a b -> (a -> b) -> StateT s m ()
%!= (a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
a)