-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.

{- |
Copyright   :  (c) 2023 Yamada Ryo
License     :  MPL-2.0 (see the file LICENSE)
Maintainer  :  ymdfield@outlook.jp
Stability   :  experimental
Portability :  portable

Interpreter for the t'Control.Effect.Class.State.State' effect class.
-}
module Control.Effect.Handler.Heftia.State where

import Control.Effect.Class (type (~>))
import Control.Effect.Class.State (StateI (Get, Put))
import Control.Effect.Freer (Fre, interpretT)
import Control.Monad.State (StateT)
import Control.Monad.Trans.State (runStateT)
import Control.Monad.Trans.State qualified as T
import Data.Tuple (swap)

-- | Interpret the 'Get'/'Put' effects using the 'StateT' monad transformer.
interpretState :: forall s es m a. Monad m => s -> Fre (StateI s ': es) m a -> Fre es m (s, a)
interpretState :: forall s (es :: [* -> *]) (m :: * -> *) a.
Monad m =>
s -> Fre (StateI s : es) m a -> Fre es m (s, a)
interpretState s
s Fre (StateI s : es) m a
a = forall a b. (a, b) -> (b, a)
swap forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (forall s (es :: [* -> *]) (m :: * -> *).
Monad m =>
Fre (StateI s : es) m ~> StateT s (Fre es m)
interpretStateT Fre (StateI s : es) m a
a) s
s
{-# INLINE interpretState #-}

evalState :: forall s es m a. Monad m => s -> Fre (StateI s ': es) m a -> Fre es m a
evalState :: forall s (es :: [* -> *]) (m :: * -> *) a.
Monad m =>
s -> Fre (StateI s : es) m a -> Fre es m a
evalState s
s Fre (StateI s : es) m a
a = forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (es :: [* -> *]) (m :: * -> *) a.
Monad m =>
s -> Fre (StateI s : es) m a -> Fre es m (s, a)
interpretState s
s Fre (StateI s : es) m a
a
{-# INLINE evalState #-}

execState :: forall s es m a. Monad m => s -> Fre (StateI s ': es) m a -> Fre es m s
execState :: forall s (es :: [* -> *]) (m :: * -> *) a.
Monad m =>
s -> Fre (StateI s : es) m a -> Fre es m s
execState s
s Fre (StateI s : es) m a
a = forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (es :: [* -> *]) (m :: * -> *) a.
Monad m =>
s -> Fre (StateI s : es) m a -> Fre es m (s, a)
interpretState s
s Fre (StateI s : es) m a
a
{-# INLINE execState #-}

-- | Interpret the 'Get'/'Put' effects using the 'StateT' monad transformer.
interpretStateT :: forall s es m. Monad m => Fre (StateI s ': es) m ~> StateT s (Fre es m)
interpretStateT :: forall s (es :: [* -> *]) (m :: * -> *).
Monad m =>
Fre (StateI s : es) m ~> StateT s (Fre es m)
interpretStateT = forall (t :: (* -> *) -> * -> *)
       (fr :: (* -> *) -> (* -> *) -> * -> *) (u :: [* -> *] -> * -> *)
       (e :: * -> *) (es :: [* -> *]) (f :: * -> *).
(MonadTransFreer fr, Union u, MonadTrans t, Monad f,
 Monad (t (FreerEffects fr u es f))) =>
(e ~> t (FreerEffects fr u es f))
-> FreerEffects fr u (e : es) f ~> t (FreerEffects fr u es f)
interpretT \case
    StateI s x
Get -> forall (m :: * -> *) s. Monad m => StateT s m s
T.get
    Put s
s -> forall (m :: * -> *) s. Monad m => s -> StateT s m ()
T.put s
s
{-# INLINE interpretStateT #-}