In those cases it's best to look at the class (MonadReader) here.
There you'll find this:
class Monad m => MonadReader r m | m -> r where
and quite a bit more.
So here m is some monad and r will be the thing you read from (MonadReader is a so called monad-transformer ... well ok not quite - it's the class that is common to all those transformers - ReaderT is the transformer ... but that's really horrible to explain ... sorry)
local is used to change the thing you read from (I like to think of it as the configuration or the environment) - the r->r part - giving you a computation in the monad m that will do this change.
And if you read on in the documentation there is even an example of how to use this:
calculateContentLen :: Reader String Int
calculateContentLen = do
content <- ask
return (length content);
-- Calls calculateContentLen after adding a prefix to the Reader content.
calculateModifiedContentLen :: Reader String Int
calculateModifiedContentLen = local ("Prefix " ++) calculateContentLen
main = do
let s = "12345";
let modifiedLen = runReader calculateModifiedContentLen s
let len = runReader calculateContentLen s
putStrLn $ "Modified 's' length: " ++ (show modifiedLen)
putStrLn $ "Original 's' length: " ++ (show len)
as you can see local is used here to add "Prefix " in front of the string
please note that the monad m in this example is not IO - it's Identity (basically nothing - it has no effect)
(I hope it's ok to copy and paste it ... if not please let me know or remove it)