能够合并不同的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

最佳答案

您可能希望将它们层叠成堆叠的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的实例,因此您的(过度) )专用类型也将通过检查。

关于haskell - 结合ReaderT monad?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13042784/

10-10 20:13