Reputation: 393
I have 2 functions with "intersecting" interfaces:
type Config = (param1, param2)
runExe :: [String] -> ReaderT Config IO ExitCode
someAction :: [String] -> ReaderT Config (MaybeT IO) ()
Since both runExe
and someAction
carry the immutable Config, I want to pass it implicitly without doing "asking" explicitly. Something like the following:
someAction params = monadConvertor runExe ["some" , "params"]
How do I implement monadConvertor
?
As far as I understand monadConvertor needs to extract IO ExitCode then lift guard (rc == ExitSuccess)
. But i don't know if it possible.
Upvotes: 3
Views: 110
Reputation: 11963
Your monadConverter
should have the following type:
monadConverter :: ReaderT Config IO ExitCode -> ReaderT Config (MaybeT IO) ()
As you already wrote in your question, you only need to "extract" the ExitCode
, and then "lift" guard (rc == ExitCode)
, which you can do with the lift
function. The problem is now that you cannot use the ReaderT Config IO ExitCode
inside a ReaderT Config (MaybeT IO) ()
. You can fix this by using mapReaderT:
mapReaderT :: mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
Using that function, monadReader
can be implemented as follows:
monadConverter :: ReaderT Config IO ExitCode -> ReaderT Config (MaybeT IO) ()
monadConverter action = do
exitCode <- mapReaderT lift action
lift $ guard (exitCode == ExitSuccess)
Here, mapReaderT lift
has the type ReaderT Config IO ExitCode -> ReaderT Config (MaybeT IO) ExitCode
.
Upvotes: 4