能够合并不同的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 = ...
这样我就可以在同一函数中同时使用
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
的实例,因此您的(过度) )专用类型也将通过检查。关于haskell - 结合ReaderT monad?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13042784/