module ST where

import Control.Monad

newtype ST s a                      = ST(s -> (a,s))

app                                 :: ST s a -> s -> (a,s)
app (ST f)                          = f

run                                 :: ST s a -> s -> a
run st                              = fst . app st

update                              :: (s -> s) -> ST s ()
update f                            = ST (\s -> ((),f s))

get                                 :: (s -> a) -> ST s a
get f                               = ST (\s -> (f s,s))

instance Functor (ST s) where
  -- fmap                           :: (a -> b) -> ST s a -> ST s b
  fmap f st                         = ST(\s ->let (a,s') = app st s in (f a,s'))
instance Applicative (ST s) where
  -- pure                           :: a -> ST s a
  pure a                            = ST (\s -> (a,s))
  
  -- <*>                            :: ST s (a -> b) -> ST s a -> ST s b
  stf <*> stx                       = ST(\s -> 
                                          let (f,s') = app stf s
                                              (x,s'') = app stx s' in (f x,s''))
instance Monad (ST s) where
  -- (>>=)                          :: ST s a -> (a -> ST s b) -> ST s b
  st >>= f                          = ST (\s -> let (x,s') = app st s in app (f x) s')

--instance MonadTrans (ST s) where
--  lift m = ST(liftM ST m)
