How to do it...

  1. Create new project state-monad-trans using the simple Stack template:
        stack new state-monad-trans simple
  1. Open src/Main.hs. We will be adding our state transformer here.
  2. Add the following imports after the initial module declaration:
        import Data.Functor
import Control.Applicative
import Control.Monad
  1. Define the State Monad transformer. Note how we embed middle m (monad) in the type:
        newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }
  1. Define the Functor instance for our state transformer:
        instance Functor m => Functor (StateT s m) where
fmap f (StateT func) =
let stateFunc s = (\(xa,xs) -> (f xa, xs)) <$> func s
in StateT stateFunc
  1. Now, define an Applicative instance for our state transformer. We make use of the fact that the embedded monad is also an instance of Applicative and use it to lift the embedded Applicative instance, that is, m (a -> b ) -> m a -> m b  to our state related m ( (a, s) -> (b, s) ) -> m (a, s) -> m (b, s):
         instance Applicative m => Applicative (StateT s m) where

-- Use the applicative instance of the embedded applicative to
-- induce both x as well as state s into it.
pure x = let stateFunc s = pure (x, s)
in StateT stateFunc

-- Get a function from State s m (a -> b) and apply it to
-- State s m a to produce State s m b

f <*> fa =
let stateFunc s =
let sf = runStateT f s -- m (f :: a -> b, s)
sa = runStateT fa s -- m (a, s)
-- Convert m (f :: a -> b, s) to
-- m (f :: (a, s) -> (b, s) )
func (fab, _) = (\(xa, st) -> (fab xa, st))
in (func <$> sf) <*> sa
in StateT stateFunc
  1. Now, implement the monad instance for our transformer:
        instance Monad m => Monad (StateT s m) where

return = pure

sma >>= smab =
let stateFunc s =
let ma = runStateT sma s -- m (a, s)
in do
(a, s1) <- ma
runStateT (smab a) s1
in StateT stateFunc
  1. Now, define get (to get the current state) and put (to put a new state) for our transformer:
        get :: Monad m => StateT s m s
get = let stateFunc s = pure (s, s)
in StateT stateFunc

put :: Monad m => s -> StateT s m ()
put s = let stateFunc _ = pure ((), s)
in StateT stateFunc
  1. We should allow an operation in the embedded monad in the context of our state transformer. Write the function lift to embed the action into our State Monad:
        lift :: Monad m => m a -> StateT s m a
lift ma = let stateFunc s = do
a <- ma
return (a, s)
in StateT stateFunc
  1. Now, write an example in which we embed IO monad in our state transformer. To demonstrate, we simply get the current state and modify it with the supplied argument:
        example :: Int -> StateT Int IO ()
example j = do
i <- get
lift $ putStrLn $ "Current state is " ++ (show i)
put j
i' <- get
lift $ putStrLn $ "Current state is " ++ (show i')
  1. Then, use the example function in our main function:
         main :: IO ()
main = do
(_, state) <- runStateT (example 10) 100
putStrLn $ "Result state is " ++ (show state)
(_, state1) <- runStateT (example 1234) 12
putStrLn $ "Result state is " ++ (show state1)
  1. Build and execute the program:
      stack build
stack exec -- state-monad-trans
  1. You should see the following output: