Hacker News new | past | comments | ask | show | jobs | submit login

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.




Which requires sweeping changes... In most other languages it's literally a one liner where you want to log something.


It requires changing the places where you instantiate your monad transformer stack, which you should have very few of.


I don't think having very few is a good scenario. I have written a compiler and had about 10 different stacks. Changing every single one just to be able to add a logger to a single function somewhere is honestly insane.

What I see in the wild is having one huge kitchen sink stack which sucks as well.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: