{-# LANGUAGE TupleSections, NoMonomorphismRestriction #-}
-- |A module extending the functionality of the State Monad with Views
module Control.Monad.State.View (
module Control.Monad.State,
module Data.View,
-- * Views with State
viewState
,viewing,modifying,getting,putting
,swappingWith,swapping
,saving
) where
import Data.View
import Control.Monad.State
-- | Constructs a State monad that acts on a View.
viewState (View v v') run = state (\s -> let ~(x,s') = run (v s) in (x,v' s' s))
-- | Executes a state restricted to the given View.
viewing v st = viewState v (runState st)
-- | Modifies the view by the given function. @modifying v f@ is equivalent to @viewing v (modify f)@.
modifying v f = viewState v (\s -> ((),f s))
-- | Gets the given view from the whole state
getting v = gets (extract v)
-- | Injects the given value into the whole state. @putting v x@ is equivalent to @viewing v (put x)@.
putting f v = modifying f (const v)
-- | @saving v m@ executes @m@, while preserving the value of the View @v@.
saving v m = getting v >>= \x -> m >>= \m -> putting v x >> return m
-- | @swappingWith v f m@ executes @m@ in an environment where the view @v@ was modified by @f@,
-- preserving the old value of @v@ (it swaps the old value and the new, and then swaps back after @m@)
swappingWith v f m = saving v (modifying v f >> m)
-- | A special case of 'swappingWith' with a constant value.
swapping v s = swappingWith v (const s)