packages feed

functor-monad-0.1.1.0: src/FMonad/State/Day.hs

{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DeriveFunctor #-}

module FMonad.State.Day
  (StateT(..),
   flift,
   toOuter, fromOuter, toInner, fromInner,
   
   State, state, state_, get, put,
   runState
) where

import Control.Monad.Trans.Identity
import Data.Functor.Day ( Day(..), day )
import Data.Functor.Day.Curried ( Curried(Curried) )
import Data.Functor.Day.Comonoid

import FMonad
import FMonad.Adjoint
import FStrong

import qualified FMonad.State.Simple.Inner as Simple.Inner
import qualified FMonad.State.Simple.Outer as Simple.Outer

import Data.Functor.Day.Extra
import Data.Coerce (coerce)
import Data.Functor.Identity
import Data.Function ((&))

newtype StateT s mm x a = StateT { runStateT :: forall r. s (a -> r) -> mm (Day s x) r }
   deriving stock Functor
   deriving (FFunctor, FMonad) via (AdjointT (Day s) (Curried s) mm)

toAdjointT :: StateT s mm x ~> AdjointT (Day s) (Curried s) mm x
toAdjointT = coerce

fromAdjointT :: AdjointT (Day s) (Curried s) mm x ~> StateT s mm x
fromAdjointT = coerce

flift :: (Functor s, FStrong mm, Functor x)
  => mm x ~> StateT s mm x
flift mm = StateT $ \sf -> fstrength' (day sf mm)

toOuter :: (Functor x, FFunctor mm) => StateT ((,) s0) mm x ~> Simple.Outer.StateT s0 mm x
toOuter = Simple.Outer.fromAdjointT . AdjointT . ffmap (ffmap dayToEnv) . curriedToReader . runAdjointT . toAdjointT

fromOuter :: (Functor x, FFunctor mm) => Simple.Outer.StateT s0 mm x ~> StateT ((,) s0) mm x
fromOuter = fromAdjointT . AdjointT . ffmap (ffmap envToDay) . readerToCurried . runAdjointT . Simple.Outer.toAdjointT

toInner :: (Functor x, FFunctor mm) => StateT ((->) s1) mm x ~> Simple.Inner.StateT s1 mm x
toInner = Simple.Inner.fromAdjointT . AdjointT . ffmap (ffmap dayToTraced) . curriedToWriter . runAdjointT . toAdjointT

fromInner :: (Functor x, FFunctor mm) => Simple.Inner.StateT s1 mm x ~> StateT ((->) s1) mm x
fromInner = fromAdjointT . AdjointT . ffmap (ffmap tracedToDay) . writerToCurried . runAdjointT . Simple.Inner.toAdjointT

type State s = StateT s IdentityT

state :: (FMonad mm)
  => (forall r. s (a -> r) -> Day s x r)
  -> StateT s mm x a
state f = StateT $ \sar -> fpure (f sar)

state_ :: (Functor s, FMonad mm)
  => (forall b. s b -> (s b, x a))
  -> StateT s mm x a
state_ f = state (uncurry day . f)

get :: (Comonoid s, FMonad mm) => StateT s mm s ()
get = state (fmap ($ ()) . coapply)

put :: (Comonad s, FMonad mm) => s a -> StateT s mm Identity a
put sa = state (\sar -> Day sa (Identity (extract sar)) (&))

runState :: State s x a -> s (a -> r) -> Day s x r
runState sx = runIdentityT . runStateT sx