如何组合不同的Monad堆栈?

时间:2014-05-17 11:57:59

标签: haskell monad-transformers

我有2个具有“交叉”接口的功能:

type Config = (param1, param2)

runExe :: [String] -> ReaderT Config IO ExitCode
someAction :: [String] -> ReaderT Config (MaybeT IO) ()

由于runExesomeAction都带有不可变的Config,我想隐式传递它而不明确地“询问”。如下所示:

 someAction params = monadConvertor runExe ["some" , "params"]

如何实施monadConvertor

据我所知,monadConvertor需要提取IO ExitCode然后解除guard (rc == ExitSuccess)。但我不知道是否有可能。

1 个答案:

答案 0 :(得分:4)

您的monadConverter应具有以下类型:

monadConverter :: ReaderT Config IO ExitCode -> ReaderT Config (MaybeT IO) ()

正如您在问题中所写的那样,您只需要“提取”ExitCode,然后“提升”guard (rc == ExitCode),您就可以使用lift功能。现在的问题是您无法在ReaderT Config IO ExitCode内使用ReaderT Config (MaybeT IO) ()。您可以使用mapReaderT

解决此问题
mapReaderT :: mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b

使用该功能,monadReader可以按如下方式实施:

monadConverter :: ReaderT Config IO ExitCode -> ReaderT Config (MaybeT IO) ()
monadConverter action = do
  exitCode <- mapReaderT lift action
  lift $ guard (exitCode == ExitSuccess)

此处,mapReaderT lift的类型为ReaderT Config IO ExitCode -> ReaderT Config (MaybeT IO) ExitCode