Reputation: 333
I'm using the ReaderT Monad transformer to propagate my configuration data from my main function through several functions performing IO. The ultimate function that will need the data doesn't perform any IO. I have this working solution :
import Control.Monad.Reader
type Configuration = String
funNoIO :: Reader Configuration String
funNoIO = do
config <- ask
return $ config ++ "!"
funIO :: ReaderT Configuration IO String
funIO = do
config <- ask
return $ runReader funNoIO config
main :: IO ()
main = do
c <- runReaderT funIO "configuration"
print c
But it forces me to retrieve the configuration in the funIO
function where I don't need it.
I modified it like this :
funIO' :: ReaderT Configuration IO String
funIO' = do
v <- funNoIO
return v
but it doesn't compile and I'm getting this error :
Couldn't match type ‘ReaderT Configuration Identity String’
with ‘Identity (ReaderT Configuration IO String)’
Expected type: Identity (ReaderT Configuration IO String)
Actual type: Reader Configuration String
In the first argument of ‘runIdentity’, namely ‘funNoIO’
In a stmt of a 'do' block: v <- runIdentity funNoIO
Is it possible to propagate my configuration data to a pure function without retrieving it in the intermediary IO functions?
EDIT
I parameterised my functions but I still can't perform an IO action in the funIO'
function. For example :
getMessage :: IO String
getMessage = do
return "message"
funIO' :: MonadIO m => ReaderT Configuration m String
funIO' = do
m <- getMessage
v <- funNoIO
return $ v ++ m
is giving me the following error :
Couldn't match type ‘IO’ with ‘ReaderT Configuration m’
Expected type: ReaderT Configuration m String
Actual type: IO String
EDIT 2
I got it, I just needed to use liftIO
:
getMessage :: IO String
getMessage = do
return "message"
funIO' :: MonadIO m => ReaderT Configuration m String
funIO' = do
m <- liftIO getMessage
v <- funNoIO
return $ v ++ m
Upvotes: 3
Views: 546
Reputation: 18189
Another way is to use the reader
method of MonadReader
together with runReader
:
funIO = reader $ runReader funNoIO
reader . runReader
converts from the pure Reader
monad to a more general MonadReader
instance.
Upvotes: 3
Reputation: 144136
You can change the type of funNoIO
and funIO
to be parameterised over the monad type since they aren't used:
funNoIO :: Monad m => ReaderT Configuration m String
funIO' :: Monad m => ReaderT Configuration m String
to fix the compiler error, then you can change main
to:
main = do
c <- runReaderT funIO' "configuration"
print c
Upvotes: 2