If you just want to add logging to existing operations, reinterpret them at the call site. Something like this
newtype LoggedStateT s m a = LoggedStateT (WriterT s (StateT s m) a)
instance (Monoid s, Monad m) => MonadState s (LoggedStateT s m) where
get = LoggedStateT $ do
val <- lift get
tell val
return val
put s = LoggedStateT $ tell s >> lift (put s)
(which is basically an ad hoc effect system)If on the other hand you want to reproduce the behavior of other languages, throw everything in `MyAppMonad` give it whatever capabilities you need.