结合ReaderT monads?

时间:2012-10-24 03:53:32

标签: haskell monads

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

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

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

这看起来像一个不错的可重用组件。那么我该如何将这个定义与另一个ReaderT环境集成,以便我可以同时使用它们呢?

例如,假设我想将它与此ReaderT实例结合使用:

foo :: ReaderT Text IO ()
foo = ...

这样我就可以在同一个函数中同时使用foologit

1 个答案:

答案 0 :(得分:1)

你会想要将它们分层堆叠成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的实例,那么你的(过度)专业类型也将通过检查器。