MonadReader without functional dependency

Is there a version of MonadReader in a library somewhere that doesn't have the functional dependency from m -> r?

If I have a function that requires reader contexts A, B and C, and I want to call a function that requires reader contexts A and C, it seems to be that I have bundle all my contexts up into a structure like (A, B, C), split them and recombine them in (A, C) to pass into another function.

This seems to go against how constraints generally compose.

Like if I have a functions:

f :: (C1 a, C2 a) => a -> a
g :: (C2 a, C3 a) => a -> a


h :: (C1 a, C2 a, C3 a) => a -> a
h = g . f

Is perfectly fine.

But if I try:

f :: (MonadReader C1 m, MonadReader C2 m) => m a -> m a
g :: (MonadReader C2 m, MonadReader C3 m) => m a -> m a


h :: (MonadReader C1 m, MonadReader C2 m, MonadReader C3 m) => m a -> m a
h = g . f

this is going to spit the dummy, because of that pesky functional dependency.

I understand that without the functional dependency, ask may require type annotations, but this is a reasonable compromise in my case, particularly when simply using the output of ask elsewhere determines it's type.

Is there a version of MonadReader without this functional dependency? Or do I need to roll my own? Or is there some other approach than just manually pulling apart/putting together tuples (in which case I feel I might as well just pass the context explicitly as the first argument).


  • There's lensy stuff for this via the Magnify type class.

    magnify :: ((b -> k c b) -> a -> k c a) -> m c -> n c

    Run a monadic action in a larger environment than it was defined in, using a Getter. [For example,]

    magnify :: Monoid w => Getter s t -> RWST s w st c -> RWST t w st c

    I've also developed effect-stack as a sort of proof-of-concept alternative approach, though as far as I know there are currently exactly zero users -- not even me.

    If a transformer stack includes two transformers that provide the given effect, mtl does not provide a clean way to disambiguate which one is wanted; the topmost one is always chosen.

    This package provides tools for disambiguating without being forced to choose a particular transformer stack.