似乎能够组合不同的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。
发布于 2013-01-31 00:58:45
您可能希望将它们层叠成一个堆叠的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的一个实例,那么您(过度)专门化的类型也将通过检查器。
https://stackoverflow.com/questions/13042784
复制相似问题