0

我使用 MongoDB 库来处理来自 Mongodb 的数据。有一个称为Action表示 DB 读取或写入操作的 Monad https://github.com/TonyGen/mongoDB-haskell/blob/master/doc/tutorial.md。但是,我发现当我在 monad Action 中时,我也想做一些必须在 IO Monad 中的 IO。一些代码如

-- `Action' is a Monad
--
intoFile :: String -> Cursor -> Action IO ()
intoFile ric c = do
  outH <- liftIO $ openFile ric AppendMode
  liftIO $ hPutStrLn outH "Some log"
  loopIntoFile outH c
  liftIO $ hClose outH

liftIO在任何单子之前都有一个IO,我认为它可能很冗长。有什么简洁的方法来处理这个吗?

4

2 回答 2

3

不幸的是,您无法避免liftIO,因为标准IO操作不会在任何MonadIO. IO但是您可以在一次调用下加入一系列操作liftIO

intoFile :: String -> Cursor -> Action IO ()
intoFile ric c = do
  outH <- liftIO $ do
    openFile ric AppendMode
    hPutStrLn outH "Some log"
  loopIntoFile outH c
  liftIO $ hClose outH

或者,如果您打算IO重复使用相同的操作,您可以为它们引入辅助定义:

intoFile :: String -> Cursor -> Action IO ()
intoFile ric c = do
  outH <- openLog ric AppendMode
  log outH "Some log"
  loopIntoFile outH c
  closeLog outH

openLog path mode = liftIO (openFile path mode)
log handle message = liftIO (hPutStrLn handle message)
closeLog handle = liftIO (hClose handle)
于 2015-04-02T16:29:40.573 回答
0

您想要携带 2 个额外的上下文 -IO上下文和Action上下文。monad 转换器就是这种情况,因为它们允许您处理分层 monad 并在do块内部选择哪个 monad 来选择所需的操作。这里很好地解释了我们为什么需要它们以及如何使用它们。

于 2015-04-02T15:51:23.203 回答