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
Then
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
Then
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.