{-# LANGUAGE TemplateHaskell #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Effect.State.Lazy
-- Copyright   :  (c) Michael Szvetits, 2020
-- License     :  BSD3 (see the file LICENSE)
-- Maintainer  :  typedbyte@qualified.name
-- Stability   :  stable
-- Portability :  portable
--
-- Lazy interpretations of the 'State'' effect.
--
-- If you don't require disambiguation of multiple state effects
-- (i.e., you only have one state effect in your monadic context),
-- you usually need the untagged interpretations.
-----------------------------------------------------------------------------
module Control.Effect.State.Lazy
  ( -- * Tagged Interpretations
    evalState'
  , execState'
  , runState'
    -- * Untagged Interpretations
  , evalState
  , execState
  , runState
  ) where

-- base
import Data.Tuple (swap)

-- transformers
import Control.Monad.Trans.State.Lazy (StateT, runStateT)

import Control.Effect.State     (State, State')
import Control.Effect.Machinery (Via, makeUntagged, runVia)

-- | Runs the state effect and discards the final state.
evalState' :: forall tag s m a. Functor m
           => s                                 -- ^ The initial state.
           -> (State' tag s `Via` StateT s) m a -- ^ The program whose state effect should be handled.
           -> m a                               -- ^ The program with its state effect handled.
evalState' :: s -> Via (State' tag s) (StateT s) m a -> m a
evalState' s
s = ((a, s) -> a) -> m (a, s) -> m a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, s) -> a
forall a b. (a, b) -> a
fst (m (a, s) -> m a)
-> (Via (State' tag s) (StateT s) m a -> m (a, s))
-> Via (State' tag s) (StateT s) m a
-> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StateT s m a -> s -> m (a, s)) -> s -> StateT s m a -> m (a, s)
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT s
s (StateT s m a -> m (a, s))
-> (Via (State' tag s) (StateT s) m a -> StateT s m a)
-> Via (State' tag s) (StateT s) m a
-> m (a, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Via (State' tag s) (StateT s) m a -> StateT s m a
forall (effs :: [Effect]) (t :: Transformer) (m :: * -> *) a.
EachVia effs t m a -> t m a
runVia
{-# INLINE evalState' #-}

-- | Runs the state effect and discards the result of the interpreted program.
execState' :: forall tag s m a. Functor m
           => s                                 -- ^ The initial state.
           -> (State' tag s `Via` StateT s) m a -- ^ The program whose state effect should be handled.
           -> m s                               -- ^ The program with its state effect handled, producing the final state @s@.
execState' :: s -> Via (State' tag s) (StateT s) m a -> m s
execState' s
s = ((a, s) -> s) -> m (a, s) -> m s
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, s) -> s
forall a b. (a, b) -> b
snd (m (a, s) -> m s)
-> (Via (State' tag s) (StateT s) m a -> m (a, s))
-> Via (State' tag s) (StateT s) m a
-> m s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StateT s m a -> s -> m (a, s)) -> s -> StateT s m a -> m (a, s)
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT s
s (StateT s m a -> m (a, s))
-> (Via (State' tag s) (StateT s) m a -> StateT s m a)
-> Via (State' tag s) (StateT s) m a
-> m (a, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Via (State' tag s) (StateT s) m a -> StateT s m a
forall (effs :: [Effect]) (t :: Transformer) (m :: * -> *) a.
EachVia effs t m a -> t m a
runVia
{-# INLINE execState' #-}

-- | Runs the state effect and returns both the final state and the result of the interpreted program.
runState' :: forall tag s m a. Functor m
          => s                                 -- ^ The initial state.
          -> (State' tag s `Via` StateT s) m a -- ^ The program whose state effect should be handled.
          -> m (s, a)                          -- ^ The program with its state effect handled, producing the final state @s@ and the result @a@.
runState' :: s -> Via (State' tag s) (StateT s) m a -> m (s, a)
runState' s
s = ((a, s) -> (s, a)) -> m (a, s) -> m (s, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, s) -> (s, a)
forall a b. (a, b) -> (b, a)
swap (m (a, s) -> m (s, a))
-> (Via (State' tag s) (StateT s) m a -> m (a, s))
-> Via (State' tag s) (StateT s) m a
-> m (s, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StateT s m a -> s -> m (a, s)) -> s -> StateT s m a -> m (a, s)
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT s m a -> s -> m (a, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT s
s (StateT s m a -> m (a, s))
-> (Via (State' tag s) (StateT s) m a -> StateT s m a)
-> Via (State' tag s) (StateT s) m a
-> m (a, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Via (State' tag s) (StateT s) m a -> StateT s m a
forall (effs :: [Effect]) (t :: Transformer) (m :: * -> *) a.
EachVia effs t m a -> t m a
runVia
{-# INLINE runState' #-}

makeUntagged ['evalState', 'execState', 'runState']