3

我正在尝试在 splice 中使用 mongodb haskell 驱动程序(快照驱动程序似乎因 snap > 0.5 而损坏)访问 mongo。

这是我到目前为止所获得的:

testSplice :: Splice AppHandler
testSplice = do
  record <- liftIO $ do
    pipe <- runIOE $ connect (host "127.0.0.1") 
    results <- access pipe master "db" (find $ select [] "coll")
    close pipe
    rest result

  return $ [TextNode $ T.pack $ show $ records]

我知道我需要在那里使用 liftIO ,因为 mongo 动作发生在 IO monad 中,我想把它拉回来。我的理解崩溃的地方是编译该拼接的结果:

Couldn't match expected type `IO a0'
    with actual type `Action m0 [Database.MongoDB.Document]'

很抱歉发布“请向我发送代码”问题,但我不知所措:我哪里出错了,我该如何完成这项工作?

4

2 回答 2

5

这是用类型签名注释的函数。我认为这很清楚问题出在哪里。

testSplice :: Splice AppHandler
testSplice = do
  record <- liftIO $ do
    pipe <- runIOE $ connect (host "127.0.0.1") -- :: IO Pipe
    results <- access pipe master "db" (find $ select [] "coll")
    -- ^ :: IO (Either Failure Cursor)
    close pipe -- :: IO ()
    rest result -- :: Action m [Document]

  return $ [TextNode $ T.pack $ show $ records]

“liftIO $ do”块内的所有内容都必须是一个 IO 操作。最后一行“休息结果”不是。一种解决方案是在该行前面加上'access pipe master "db"',就像你对 find 所做的那样。另一种解决方案是避免两次调用“访问管道...”并将查找行替换为以下内容:

result <- access pipe master "db" (find (select [] "coll") >>= rest)

然后将“rest result”行替换为“return result”

Daniel 所说的不需要 liftIO 的 find 行是正确的,但在这种情况下,这并不重要,因为 IO 有一个 MonadIO 实例。因此,将所有 liftIO 内容放在一个块中可能同样容易。

于 2011-11-21T02:35:31.647 回答
2

我不是 MongoDB 专家,所以我不能 100% 确定(我也无法测试它),但我怀疑你liftIO的位置错误。我们有liftIO :: MonadIO m => IO a -> m a,所以我们应该适用liftIO于实际上是IO但我们想要比它更大的行为IO。我怀疑这access是一个大于IO返回类型的函数。假设runIOE,closerestall 实际上都有IO返回类型,我们会做这样的事情:

testSplice = do
    pipe <- liftIO . runIOE $ connect (host "127.0.0.1")
    results <- access pipe master "db" (find $ select [] "coll") -- note: no liftIO on this one because it's presumably already lifted
    liftIO $ close pipe
    record <- liftIO $ rest result
    return [TextNode . T.pack . show $ records]

如果其中一些操作实际上不是IO事物,那么您可以liftIO从这些操作中删除。

正如您所观察到的,这可以稍微清理一下:任何以开头的相邻行都liftIO可以合并。因此,如果上面的结果证明是liftIOs 的正确位置,那么它也可以写成:

testSplice = do
    pipe <- liftIO . runIOE $ connect (host "127.0.0.1")
    results <- access pipe master "db" (find $ select [] "coll")
    liftIO $ do
        close pipe
        record <- rest result
        return [TextNode . T.pack . show $ records]

(最后一个是可以的,因为return = liftIO . return对于任何理智的实现liftIO。)

于 2011-11-19T19:52:27.240 回答