结合ReaderT monads?

3

看起来,能够组合不同的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


2
请查看此帖子 - Bruno Grieder
1个回答

1
你需要将它们分层到一个堆叠的monad中,但它们不能被堆叠在一起,因为它们都声明IO是包装的monad。幸运的是,你的代码已经足够通用,可以解除这个限制。你的函数最通用的类型使用MonadIO而不是特定地使用IO。如果你把类型改成
 logit :: MonadIO m => Text -> ReaderT Bool m ()
 foo   :: MonadIO m =>         ReaderT Text m ()

如果使用liftIO调用,它将把IO操作提升到整个堆栈中的底部IO单子上。需要说明的是,你编写的类型不需要使用liftIO,只使用lift即可满足相同的类型,但由于IO是(显然)MonadIO实例,因此你过度特化的类型也将通过检查器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接