-----------------------------------------------------------------------------
-- |
-- module      :  Control.Monad.Trans.State
-- Copyright   :  (c) Evgeniy Permyakov 2010
-- License     :  BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  :  permeakra@gmail.com
-- Stability   :  experimental 
-- Portability :  portable (haskell - 2010)

-- this module implements lazy state monad: a monad, threading updateable state
module Control.Monad.Trans.State.Lazy (StateT, runStateT, get, put) where
import Control.Monad.Trans.Class
import Control.Monad.IO.Class


-- | threading state through computations 
newtype StateT s m a = StateT ( s -> m (s, a) )  

stateT :: (s -> m (s,a) ) -> StateT s m a
stateT = StateT

-- | run stateful computation
runStateT :: StateT s m a -> s -> m (s, a)
runStateT (StateT f) s = f s

instance Functor m => Functor (StateT s m) where 
 fmap f (StateT c) = StateT $ \s -> fmap ( \(~(s',a)) -> (s', f a) ) $ c s

instance Monad m => Monad (StateT s m) where
 return a = stateT $ \s -> return (s , a)
 m >>= k  = stateT $ \s -> do
 		~(s',ma) <- runStateT m s
		runStateT (k ma) s'

instance MonadTrans (StateT s) where
 lift m = stateT $ \s -> m >>= \a -> return (s,a)

instance MonadIO m => MonadIO (StateT s m) where
 liftIO = lift . liftIO


-- | extract value from context
get :: Monad m => StateT s m s
get = stateT $ \s -> return (s,s)

-- | put value to context, overwriting previous one
put :: Monad m => s -> StateT s m ()
put s = stateT $ \_ -> return (s, ())






