content: {-# LANGUAGE EmptyDataDecls #-}
  {-# LANGUAGE RankNTypes     #-}
  
  module Monad2 where
  
  main :: Fay ()
  main = do
    -- State monad test
    return (let result = runState demo 60 in fst result ++ ": " ++ show (snd result)) >>= putStrLn
  
  --------------------------------------------------------------------------------
  -- A monad interface
  
  data MonadI m = Monad
    (forall a. a -> m a)
    (forall a b. m a -> (a -> m b) -> m b)
    (forall a b. m a -> m b -> m b)
  
  ---------------------------------------------------------------------------------
  -- State monad
  
  -- Example
  
  demo =
    case stateMonad of
      Monad return (>>=) (>>) -> do
        n <- get
        put (n*2)
        n <- get
        put (n+3)
        return "abc"
  
  -- Definition
  
  data State s a = State { runState :: s -> (a, s) }
  instance Monad (State a)
  
  stateMonad = Monad return (>>=) (>>) where
    return = \x -> State ( \st -> (x, st) )
    (>>=) = \processor processorGenerator ->
              State $ \st ->
                case runState processor st of
                  (x, st') -> runState (processorGenerator x) st'
    (>>) = \a b -> a >>= \_ -> b
  
  put newState = State $ \_ -> ((), newState)
  
  get = State $ \st -> (st, st)
  