A somewhat more mathematical argument:
Consider what happens when you modify the environment. For instance, say you have an environment with an Int
in in, but your Reader
requires an Integer
. I.e., you have
yourReader :: Reader Integer A
Well, clearly you can convert the Int
in the environment, just use
fromIntegral :: Int -> Integer
But what this means for your reader monad is that you convert to Reader Int A
, because only that type works in your original environment.
yourReader' :: Reader Int A
yourReader' = withReader fromIntegral yourReader
Mathematicians describe this by saying Reader
is contravariant in its first argument. But if it consisted of just a variable for the value and one for the environment, then it would be covariant in both arguments (i.e. Int -> Integer
would transform Reader Int A
to Reader Integer A
, not the other way around). Whereas a function type is contravariant in its left side.