module Control.Monad.Trans.StateBag.Pure (
StateBaggerT,
runBagger,
addItem,
topItem,
stackItem,
StateBagT,
makeBag,
getItem,
putItem,
modifyItemM,
ElementCount(),
ElementIndex(),
) where
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Trans.State
import Control.Monad.Trans.StateBag.Internal
import Control.Monad.IO.Class
import Control.Monad.Primitive
import Data.Proxy
import GHC.Prim (Any, unsafeCoerce#)
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
newtype BaggerImpl (bag :: [*]) = BaggerImpl [Any]
newtype StateBaggerT bag m a = StateBaggerT (StateT (BaggerImpl bag) m a)
deriving (Functor, Applicative, Monad, MonadIO)
instance MonadTrans (StateBaggerT bag) where
lift = StateBaggerT . lift
instance (PrimMonad m) => PrimMonad (StateBaggerT bag m) where
type PrimState (StateBaggerT bag m) = PrimState m
primitive = lift . primitive
runBagger :: (Monad m) => StateBaggerT '[] m a -> m a
runBagger (StateBaggerT s) =
fmap fst $ runStateT s $ BaggerImpl []
addItem :: forall item bag m a. (Monad m) =>
item -> StateBaggerT (item ': bag) m a -> StateBaggerT bag m a
addItem item (StateBaggerT chain) = StateBaggerT $ do
(BaggerImpl list) <- get
(ret, BaggerImpl (_:list')) <- lift $ runStateT chain $
BaggerImpl (unsafeCoerce# item : list)
put $ BaggerImpl list'
return ret
topItem :: forall item bag m. (Monad m) =>
StateBaggerT (item ': bag) m item
topItem = StateBaggerT $ do
(BaggerImpl (item:_)) <- get
return $ unsafeCoerce# item
stackItem :: forall item bag m a. (Monad m) =>
item -> StateBaggerT (item ': bag) m a -> StateBaggerT bag m (a, item)
stackItem item chain =
addItem item $ liftM2 (,) chain topItem
newtype BagImpl (bag :: [*]) = BagImpl (V.Vector Any)
newtype StateBagT bag m a = StateBagT (StateT (BagImpl bag) m a)
deriving (Functor, Applicative, Monad, MonadIO)
instance MonadTrans (StateBagT bag) where
lift = StateBagT . lift
instance (PrimMonad m) => PrimMonad (StateBagT bag m) where
type PrimState (StateBagT bag m) = PrimState m
primitive = lift . primitive
makeBag ::
forall bag m a. (Monad m, ElementCount bag) =>
StateBagT bag m a -> StateBaggerT bag m a
makeBag (StateBagT s) = StateBaggerT $ do
(BaggerImpl list) <- get
let vlen = elemCount (Proxy :: Proxy bag)
(ret, BagImpl vec') <- lift $ runStateT s $ BagImpl $ V.fromListN vlen list
put $ BaggerImpl $ V.toList vec'
return ret
itemImpl :: forall m item bag.
(Monad m, ElementIndex item bag) =>
StateBagT bag m (item, item -> StateBagT bag m ())
itemImpl = do
let i = elemIndex (Proxy :: Proxy item) (Proxy :: Proxy bag)
(BagImpl vec) <- StateBagT get
let item = unsafeCoerce# $ (V.!) vec i
let puti item' = StateBagT $ put $ BagImpl $ V.modify (\mvec ->
MV.write mvec i $ unsafeCoerce# item') vec
return (item, puti)
getItem :: forall m item bag.
(Monad m, ElementIndex item bag) =>
StateBagT (bag :: [*]) m item
getItem = fmap fst itemImpl
putItem :: forall m item bag.
(Monad m, ElementIndex item bag) =>
item -> StateBagT (bag :: [*]) m ()
putItem item = itemImpl >>= flip snd item
modifyItemM :: forall m item bag.
(Monad m, ElementIndex item bag) =>
(item -> StateBagT bag m item) -> StateBagT bag m ()
modifyItemM f = do
(item, puti) <- itemImpl
item' <- f item
puti item'