linear-base-0.1.0: src/Control/Functor/Linear/Internal/State.hs
{-# OPTIONS_HADDOCK hide #-}
{-# OPTIONS -Wno-orphans #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module Control.Functor.Linear.Internal.State
( StateT(..)
, State
, state
, get, put, gets
, modify
, replace
, runStateT, runState
, mapStateT, mapState
, execStateT, execState
, withStateT, withState
) where
import Prelude.Linear.Internal
import Data.Unrestricted.Internal.Consumable
import Data.Unrestricted.Internal.Dupable
import Control.Functor.Linear.Internal.MonadTrans
import Control.Functor.Linear.Internal.Class
import Control.Functor.Linear.Internal.Instances ( Data(..) )
import qualified Data.Functor.Linear.Internal.Functor as Data
import qualified Data.Functor.Linear.Internal.Applicative as Data
import qualified Control.Monad.Trans.State.Strict as NonLinear
import qualified Control.Monad as NonLinear ()
import Data.Functor.Identity
-- # StateT
-------------------------------------------------------------------------------
-- | A (strict) linear state monad transformer.
newtype StateT s m a = StateT (s %1-> m (a, s))
deriving Data.Applicative via Data (StateT s m)
-- We derive Data.Applicative and not Data.Functor since Data.Functor can use
-- weaker constraints on m than Control.Functor, while
-- Data.Applicative needs a Monad instance just like Control.Applicative.
type State s = StateT s Identity
get :: (Applicative m, Dupable s) => StateT s m s
get = state dup
put :: (Applicative m, Consumable s) => s %1-> StateT s m ()
put = Data.void . replace
gets :: (Applicative m, Dupable s) => (s %1-> a) %1-> StateT s m a
gets f = state ((\(s1,s2) -> (f s1, s2)) . dup)
runStateT :: StateT s m a %1-> s %1-> m (a, s)
runStateT (StateT f) = f
state :: Applicative m => (s %1-> (a,s)) %1-> StateT s m a
state f = StateT (pure . f)
runState :: State s a %1-> s %1-> (a, s)
runState f = runIdentity' . runStateT f
mapStateT :: (m (a, s) %1-> n (b, s)) %1-> StateT s m a %1-> StateT s n b
mapStateT r (StateT f) = StateT (r . f)
withStateT :: (s %1-> s) %1-> StateT s m a %1-> StateT s m a
withStateT r (StateT f) = StateT (f . r)
execStateT :: Functor m => StateT s m () %1-> s %1-> m s
execStateT f = fmap (\((), s) -> s) . (runStateT f)
mapState :: ((a,s) %1-> (b,s)) %1-> State s a %1-> State s b
mapState f = mapStateT (Identity . f . runIdentity')
withState :: (s %1-> s) %1-> State s a %1-> State s a
withState = withStateT
execState :: State s () %1-> s %1-> s
execState f = runIdentity' . execStateT f
modify :: Applicative m => (s %1-> s) %1-> StateT s m ()
modify f = state $ \s -> ((), f s)
-- TODO: add strict version of `modify`
-- | @replace s@ will replace the current state with the new given state, and
-- return the old state.
replace :: Applicative m => s %1-> StateT s m s
replace s = state $ (\s' -> (s', s))
-- # Instances of StateT
-------------------------------------------------------------------------------
instance Functor m => Functor (NonLinear.StateT s m) where
fmap f (NonLinear.StateT x) = NonLinear.StateT $ \s -> fmap (\(a, s') -> (f a, s')) $ x s
instance Data.Functor m => Data.Functor (StateT s m) where
fmap f (StateT x) = StateT (\s -> Data.fmap (\(a, s') -> (f a, s')) (x s))
instance Functor m => Functor (StateT s m) where
fmap f (StateT x) = StateT (\s -> fmap (\(a, s') -> (f a, s')) (x s))
instance Monad m => Applicative (StateT s m) where
pure x = StateT (\s -> return (x,s))
StateT mf <*> StateT mx = StateT $ \s -> do
(f, s') <- mf s
(x, s'') <- mx s'
return (f x, s'')
instance Monad m => Monad (StateT s m) where
StateT mx >>= f = StateT $ \s -> do
(x, s') <- mx s
runStateT (f x) s'
instance MonadTrans (StateT s) where
lift x = StateT (\s -> fmap (,s) x)