{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

{- | A carrier for the 'State' effect that refrains from evaluating its state until necessary. This is less efficient than "Control.Carrier.State.Strict" but allows some cyclic computations to terminate that would loop infinitely in a strict state carrier.

Note that the parameter order in 'runState', 'evalState', and 'execState' is reversed compared the equivalent functions provided by @transformers@. This is an intentional decision made to enable the composition of effect handlers with '.' without invoking 'flip'.

@since 1.0.0.0
-}

module Control.Carrier.State.Lazy
( -- * Lazy state carrier
  runState
, evalState
, execState
, StateC(..)
  -- * State effect
, module Control.Effect.State
) where

import Control.Algebra
import Control.Applicative (Alternative(..))
import Control.Effect.State
import Control.Monad (MonadPlus)
import Control.Monad.Fail as Fail
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class

-- | Run a lazy 'State' effect, yielding the result value and the final state. More programs terminate with lazy state than strict state, but injudicious use of lazy state may lead to thunk buildup.
--
-- @
-- 'runState' s ('pure' a) = 'pure' (s, a)
-- @
-- @
-- 'runState' s 'get' = 'pure' (s, s)
-- @
-- @
-- 'runState' s ('put' t) = 'pure' (t, ())
-- @
--
-- @since 1.0.0.0
runState :: s -> StateC s m a -> m (s, a)
runState :: forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s (StateC s -> m (s, a)
runStateC) = s -> m (s, a)
runStateC s
s
{-# INLINE[3] runState #-}

-- | Run a lazy 'State' effect, yielding the result value and discarding the final state.
--
-- @
-- 'evalState' s m = 'fmap' 'snd' ('runState' s m)
-- @
--
-- @since 1.0.0.0
evalState :: forall s m a . Functor m => s -> StateC s m a -> m a
evalState :: forall s (m :: * -> *) a. Functor m => s -> StateC s m a -> m a
evalState s
s = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s
{-# INLINE[3] evalState #-}

-- | Run a lazy 'State' effect, yielding the final state and discarding the return value.
--
-- @
-- 'execState' s m = 'fmap' 'fst' ('runState' s m)
-- @
--
-- @since 1.0.0.0
execState :: forall s m a . Functor m => s -> StateC s m a -> m s
execState :: forall s (m :: * -> *) a. Functor m => s -> StateC s m a -> m s
execState s
s = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s
{-# INLINE[3] execState #-}

-- | @since 1.0.0.0
newtype StateC s m a = StateC (s -> m (s, a))

instance Functor m => Functor (StateC s m) where
  fmap :: forall a b. (a -> b) -> StateC s m a -> StateC s m b
fmap a -> b
f StateC s m a
m = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC forall a b. (a -> b) -> a -> b
$ \ s
s -> (\ ~(s
s', a
a) -> (s
s', a -> b
f a
a)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s StateC s m a
m
  {-# INLINE fmap #-}

instance Monad m => Applicative (StateC s m) where
  pure :: forall a. a -> StateC s m a
pure a
a = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC forall a b. (a -> b) -> a -> b
$ \ s
s -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (s
s, a
a)
  {-# INLINE pure #-}

  StateC s -> m (s, a -> b)
mf <*> :: forall a b. StateC s m (a -> b) -> StateC s m a -> StateC s m b
<*> StateC s -> m (s, a)
mx = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC forall a b. (a -> b) -> a -> b
$ \ s
s -> do
    ~(s
s',  a -> b
f) <- s -> m (s, a -> b)
mf s
s
    ~(s
s'', a
x) <- s -> m (s, a)
mx s
s'
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (s
s'', a -> b
f a
x)
  {-# INLINE (<*>) #-}

  StateC s m a
m *> :: forall a b. StateC s m a -> StateC s m b -> StateC s m b
*> StateC s m b
k = StateC s m a
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a b. a -> b -> a
const StateC s m b
k
  {-# INLINE (*>) #-}

instance Monad m => Monad (StateC s m) where
  StateC s m a
m >>= :: forall a b. StateC s m a -> (a -> StateC s m b) -> StateC s m b
>>= a -> StateC s m b
k = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC forall a b. (a -> b) -> a -> b
$ \ s
s -> do
    ~(s
s', a
a) <- forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s StateC s m a
m
    forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s' (a -> StateC s m b
k a
a)
  {-# INLINE (>>=) #-}

instance (Alternative m, Monad m) => Alternative (StateC s m) where
  empty :: forall a. StateC s m a
empty = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC (forall a b. a -> b -> a
const forall (f :: * -> *) a. Alternative f => f a
empty)
  {-# INLINE empty #-}

  StateC s -> m (s, a)
l <|> :: forall a. StateC s m a -> StateC s m a -> StateC s m a
<|> StateC s -> m (s, a)
r = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC (\ s
s -> s -> m (s, a)
l s
s forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> s -> m (s, a)
r s
s)
  {-# INLINE (<|>) #-}

instance Fail.MonadFail m => Fail.MonadFail (StateC s m) where
  fail :: forall a. String -> StateC s m a
fail String
s = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC (forall a b. a -> b -> a
const (forall (m :: * -> *) a. MonadFail m => String -> m a
Fail.fail String
s))
  {-# INLINE fail #-}

instance MonadFix m => MonadFix (StateC s m) where
  mfix :: forall a. (a -> StateC s m a) -> StateC s m a
mfix a -> StateC s m a
f = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC (\ s
s -> forall (m :: * -> *) a. MonadFix m => (a -> m a) -> m a
mfix (forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState s
s forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> StateC s m a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd))
  {-# INLINE mfix #-}

instance MonadIO m => MonadIO (StateC s m) where
  liftIO :: forall a. IO a -> StateC s m a
liftIO IO a
io = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC (\ s
s -> (,) s
s forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO a
io)
  {-# INLINE liftIO #-}

instance (Alternative m, Monad m) => MonadPlus (StateC s m)

instance MonadTrans (StateC s) where
  lift :: forall (m :: * -> *) a. Monad m => m a -> StateC s m a
lift m a
m = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC (\ s
s -> (,) s
s forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a
m)
  {-# INLINE lift #-}

instance Algebra sig m => Algebra (State s :+: sig) (StateC s m) where
  alg :: forall (ctx :: * -> *) (n :: * -> *) a.
Functor ctx =>
Handler ctx n (StateC s m)
-> (:+:) (State s) sig n a -> ctx () -> StateC s m (ctx a)
alg Handler ctx n (StateC s m)
hdl (:+:) (State s) sig n a
sig ctx ()
ctx = forall s (m :: * -> *) a. (s -> m (s, a)) -> StateC s m a
StateC forall a b. (a -> b) -> a -> b
$ \ s
s -> case (:+:) (State s) sig n a
sig of
    L State s n a
Get     -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (s
s, s
s forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ ctx ()
ctx)
    L (Put s
s) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (s
s, ctx ()
ctx)
    R sig n a
other   -> forall (ctx1 :: * -> *) (ctx2 :: * -> *)
       (sig :: (* -> *) -> * -> *) (m :: * -> *) (n :: * -> *) a.
(Functor ctx1, Functor ctx2, Algebra sig m) =>
Handler (Compose ctx1 ctx2) n m
-> sig n a -> ctx1 (ctx2 ()) -> m (ctx1 (ctx2 a))
thread (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState forall (n :: * -> *) (ctx1 :: * -> *) (m :: * -> *)
       (ctx2 :: * -> *) (l :: * -> *).
(Functor n, Functor ctx1) =>
Handler ctx1 m n
-> Handler ctx2 l m -> Handler (Compose ctx1 ctx2) l n
~<~ Handler ctx n (StateC s m)
hdl) sig n a
other (s
s, ctx ()
ctx)
  {-# INLINE alg #-}