{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Trustworthy #-}
module Control.Eff.State.OnDemand where
import Control.Eff
import Control.Eff.Extend
import Control.Eff.Writer.Lazy
import Control.Eff.Reader.Lazy
import qualified Control.Eff.State.Lazy as S
import Control.Monad.Base
import Control.Monad.Trans.Control
import Data.Function (fix)
data OnDemandState s v where
Get :: OnDemandState s s
Put :: s -> OnDemandState s ()
Delay :: Eff '[OnDemandState s] a -> OnDemandState s a
instance Handle (OnDemandState s) r a (s -> k) where
handle step q sreq s = case sreq of
Get -> step (q ^$ s) s
Put s' -> step (q ^$ ()) s'
Delay m -> let ~(x, s') = run $ (fix (handle_relay S.withState)) m s
in step (q ^$ x) s'
instance ( MonadBase m m
, LiftedBase m r
) => MonadBaseControl m (Eff (OnDemandState s ': r)) where
type StM (Eff (OnDemandState 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 (OnDemandState s) r => Eff r s
get = send Get
{-# RULES
"get/bind" forall k. get >>= k = send Get >>= k
#-}
{-# NOINLINE put #-}
put :: Member (OnDemandState 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)
#-}
onDemand :: Member (OnDemandState s) r => Eff '[OnDemandState s] v -> Eff r v
onDemand = send . Delay
runState :: s
-> Eff (OnDemandState s ': r) w
-> Eff r (w,s)
runState s m = fix (handle_relay S.withState) m s
modify :: (Member (OnDemandState s) r) => (s -> s) -> Eff r ()
modify f = get >>= put . f
evalState :: s -> Eff (OnDemandState s ': r) w -> Eff r w
evalState s = fmap fst . runState s
execState :: s -> Eff (OnDemandState s ': r) w -> Eff r s
execState s = fmap snd . runState s
runStateR :: s -> Eff (Writer s ': Reader s ': r) w -> Eff r (w,s)
runStateR s (Val x) = S.withState x s
runStateR s (E q u) = case u of
U0 (Tell w) -> handle loop q (S.Put w) s
U1 (U0 Ask) -> handle loop q S.Get s
U1 (U1 u') -> relay (qComp q loop) u' s
where loop = flip runStateR
runStateBack0 :: Eff '[OnDemandState s] a -> (a,s)
runStateBack0 m =
let (x,s) = go m s in
(x,s)
where
go :: Eff '[OnDemandState s] a -> s -> (a,s)
go (Val x) s = (x,s)
go (E q u) s0 = case decomp u of
Right Get -> k s0 s0
Right (Put s1) -> let ~(x,sp) = k () sp in (x,s1)
Right (Delay m1) -> let ~(x,s1) = go m1 s0 in k x s1
Left _ -> error "Impossible happened: Nothing to relay!"
where
k = qComp q go
runStateBack :: Eff '[OnDemandState s] a -> (a,s)
runStateBack m =
let (x,(_,sp)) = run $ go m (sp,[]) in
(x,head sp)
where
go :: Eff '[OnDemandState s] a -> ([s],[s]) -> Eff '[] (a,([s],[s]))
go = fix (handle_relay' h S.withState)
h step q Get s0@(sg, _) = step (q ^$ head sg) s0
h step q (Put s1) (sg, sp) = step (q ^$ ()) (tail sg,sp++[s1])
h step q (Delay m1) s0 = let ~(x,s1) = run $ go m1 s0 in step (q ^$ x) s1