packages feed

hs-ix-0.2.0.0: Control/Monad/Indexed/Trans/State.hs

-- | The indexed state transformer: each @'StateT' _ i j@ term takes an input of type @i@ and gives an output of type @j@.

module Control.Monad.Indexed.Trans.State where

import Prelude hiding ((<*>), Monad (..))
import Control.Applicative (Alternative (..))
import qualified Control.Applicative as Base
import qualified Control.Monad as Base
import qualified Control.Monad.Fix as Base
import Control.Monad.Indexed.Signatures
import Data.Functor.Indexed

newtype StateT f i j a = StateT { runStateT :: i -> f (a, j) }
  deriving (Functor)

lift :: Functor f => f a -> StateT f k k a
lift xm = StateT $ \ k -> flip (,) k <$> xm

mapStateT :: (f (a, j) -> g (b, k)) -> StateT f i j a -> StateT g i k b
mapStateT f (StateT x) = StateT (f . x)

modify :: Applicative p => (i -> j) -> StateT p i j i
modify f = modifyF (pure . f)

modifyF :: Functor f => (i -> f j) -> StateT f i j i
modifyF = StateT . Base.liftA2 fmap (,)

get :: Applicative p => StateT p k k k
get = modifyF pure

put :: Applicative p => j -> StateT p i j ()
put = StateT . pure . pure . (,) ()

instance Base.Monad m => Apply (StateT m) where
    StateT fm <*> StateT xm = StateT $ \ i -> [(f x, k) | (f, j) <- fm i, (x, k) <- xm j]

instance Base.Monad m => Bind (StateT m) where
    join = StateT . (Base.>=> uncurry runStateT) . runStateT

instance Base.Monad m => Base.Applicative (StateT m k k) where
    pure a = StateT $ pure . (,) a
    (<*>) = (<*>)

instance Base.Monad m => Base.Monad (StateT m k k) where
    (>>=) = (>>=)

instance Base.MonadPlus m => Alternative (StateT m k k) where
    empty = StateT (pure empty)
    StateT a <|> StateT b = StateT (Base.liftA2 (<|>) a b)

instance Base.MonadPlus m => Base.MonadPlus (StateT m k k) where
    mzero = empty
    mplus = (<|>)

instance Base.MonadFix m => Base.MonadFix (StateT m k k) where
    mfix f = StateT $ Base.mfix . \ k -> flip runStateT k . f . fst

liftCallCC
 :: CallCC f g h (a, i) (b, j) (c, k) (d, l)
 -> CallCC (StateT f e j) (StateT g i k) (StateT h i l) a b c d
liftCallCC callCC f =
    StateT $ \ st ->
    callCC $ \ k ->
    runStateT (f $ \ a -> StateT $ \ _ -> k (a, st)) st

liftCatch
 :: Catch e f g h (a, i) (b, j) (c, k)
 -> Catch e (StateT f l i) (StateT g l j) (StateT h l k) a b c
liftCatch catchE (StateT xm) h = StateT $ \ st -> xm st `catchE` \ e -> runStateT (h e) st

liftListen
 :: Functor f
 => Listen w f (a, j) b
 -> Listen w (StateT f i j) a (i -> b)
liftListen listen xm = StateT $ \ st ->
    flip fmap (listen (xm st)) $ \ ~((a, st'), w) -> ((a, w), st')

liftPass
 :: Functor f
 => Pass z f g (a, k) (b, j)
 -> Pass z (StateT f i k) (StateT g i j) a b
liftPass pass (StateT xm) = StateT $ \ st ->
    pass $ flip fmap (xm st) $ \ ~((a, f), st') -> ((a, st'), f)