{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE TypeApplications #-}
module Control.Eff.State.Lazy where
import Control.Eff
import Control.Eff.Extend
import Control.Eff.Writer.Lazy
import Control.Eff.Reader.Lazy
import Control.Monad.Base
import Control.Monad.Trans.Control
import Data.Function (fix)
data State s v where
Get :: State s s
Put :: s -> State s ()
withState :: Monad m => a -> s -> m (a, s)
withState x s = return (x, s)
instance Handle (State s) r a (s -> k) where
handle step q sreq s = case sreq of
Get -> step (q ^$ s) s
Put s' -> step (q ^$ ()) s'
instance ( MonadBase m m
, LiftedBase m r
) => MonadBaseControl m (Eff (State s ': r)) where
type StM (Eff (State s ': r)) a = StM (Eff r) (a,s)
liftBaseWith f = do s <- get
raise $ liftBaseWith $ \runInBase ->
f (runInBase . runState s)
restoreM x = do (a, s :: s) <- raise (restoreM x)
put s
return a
{-# NOINLINE get #-}
get :: Member (State s) r => Eff r s
get = send Get
{-# RULES
"get/bind" forall k. get >>= k = send Get >>= k
#-}
{-# NOINLINE put #-}
put :: Member (State s) r => s -> Eff r ()
put s = send (Put s)
{-# RULES
"put/bind" forall k v. put v >>= k = send (Put v) >>= k
#-}
{-# RULES
"put/semibind" forall k v. put v >> k = send (Put v) >>= (\() -> k)
#-}
runState :: s
-> Eff (State s ': r) a
-> Eff r (a, s)
runState s m = fix (handle_relay withState) m s
modify :: (Member (State s) r) => (s -> s) -> Eff r ()
modify f = get >>= put . f
evalState :: s -> Eff (State s ': r) a -> Eff r a
evalState s = fmap fst . runState s
execState :: s -> Eff (State s ': r) a -> Eff r s
execState s = fmap snd . runState s
data TxState s v where
TxState :: TxState s s
type TxStateT s = TxState s s
withTxState :: Member (State s) r => a -> s -> Eff r a
withTxState x s = put s >> return x
transactionState :: forall s r a. Member (State s) r
=> TxStateT s -> Eff r a -> Eff r a
transactionState _ m = do
s <- get
(fix $ respond_relay @(State s) (withTxState @s)) m s
runStateR :: s -> Eff (Writer s ': Reader s ': r) a -> Eff r (a, s)
runStateR = flip loop
where
loop :: Eff (Writer s ': Reader s ': r) a -> s -> Eff r (a, s)
loop (Val x) = withState x
loop (E q u) = case u of
U0 (Tell w) -> handle loop q (Put w)
U1 (U0 Ask) -> handle loop q Get
U1 (U1 u') -> relay (qComp q loop) u'