Haskell 合并ReaderT单子?

Haskell 合并ReaderT单子?,haskell,monads,Haskell,Monads,能够组合不同的ReaderT环境似乎很有用 例如,通用日志记录工具可能如下所示: logit :: Text -> ReaderT Bool IO () logit str = do debugflag <- ask liftIO $ if debugflag then putStrLn ("debug: " ++ str) else return () 因此,我可以在同一个函数中同时使用foo和logit。您希望将它们分层到一个堆叠的monad中,

能够组合不同的ReaderT环境似乎很有用

例如,通用日志记录工具可能如下所示:

logit :: Text -> ReaderT Bool  IO ()
logit str = do debugflag <- ask
               liftIO $ if debugflag then putStrLn ("debug: " ++ str) else return ()

因此,我可以在同一个函数中同时使用
foo
logit

您希望将它们分层到一个堆叠的monad中,但它们不能堆叠在一起,因为它们都声明
IO
正是包装的monad。幸运的是,您的代码已经足够通用,可以解除此限制。最通用的函数类型使用
MonadIO
,而不是专门使用
IO
。如果将类型更改为

 logit :: MonadIO m => Text -> ReaderT Bool m ()
 foo   :: MonadIO m =>         ReaderT Text m ()
然后,
liftIO
调用将整个堆栈中的
IO
操作提升到底部的
IO
monad

需要说明的是,您编写的类型不需要使用
liftIO
——相同的类型只需
lift
,但由于
IO
MonadIO
的一个实例,因此您的(过度)专用类型也将通过检查。

请检查
 logit :: MonadIO m => Text -> ReaderT Bool m ()
 foo   :: MonadIO m =>         ReaderT Text m ()