Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why MonadReader r (StateT s m) uses an instance of the underlying monad

As far as I can see, we could implement MonadReader s (StateT s m) instance:

instance MonadReader s (StateT s m) where
    ask = get
    local f m = do
        s <- get
        put (f s)
        m
        put s   

i.e. why it isn't

class MonadReader s m => MonadState s m | s -> m where ...

Similarly we could have Monoid s => MonadWriter s (StateT s m) instance.

Is there some deep reason between the choice?


This question is motivated by whether MonadError and MonadWriter should be super classes of MonadChronicle

like image 782
phadej Avatar asked Mar 11 '23 10:03

phadej


1 Answers

Yes, you could do that, but it would violate the spirit of mtl and potentially lead to API issues. The idea of mtl is that each standard monad transformer adds one or more distinct effects. Adding StateT and ReaderT to the transformer stack give you a state and an environment. If StateT implemented its own MonadReader instance, then you'd have access to just the state blob, through two different interfaces. To add an environment to the mix, you'd have to work with the transformers "manually". If you see MonadChronicle as offering effects you might want to layer on top of writer and exception effects, then you should keep them separate. If you see it as an extension/refinement of those effects, then superclasses make sense.

like image 110
dfeuer Avatar answered Apr 30 '23 11:04

dfeuer