kubivan
kubivan

Reputation: 393

How to combine different Monad Stacks?

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

Answers (1)

bennofs
bennofs

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

Related Questions