Haskell:使Snap和LevelDB发挥得很好

时间:2014-03-04 08:55:35

标签: haskell monad-transformers haskell-snap-framework leveldb

我正在使用LevelDB库和Snap框架。我有:

main :: IO ()
main = runResourceT $ do
    db <- open "thedb" defaultOptions { createIfMissing = True }
    liftIO $ serveSnaplet defaultConfig $ initWeb db

现在在我的处理程序中,我不确定如何回到MonadResource IO以查询数据库:

handleWords :: Handler App App ()
handleWords = do
    words <- uses thedb $ \db -> $ get db def "words"
    writeBS $ pack $ show words

这给了我一个:No instance for (MonadResource IO) arising from a use of 'get'

有什么想法吗?我觉得我错过了一些关于如何正确创建monad&#34; stack&#34;的内容。感谢

2 个答案:

答案 0 :(得分:3)

MonadResource / ResourceT是获取稀缺资源的一种方式,可以保证在例外的情况下可以释放资源。另一种方法是bracket模式,Snap通过the bracketSnap function支持。您可以使用它来创建LevelDB所需的ResourceT上下文:

import qualified Control.Monad.Trans.Resource as Res
bracketSnap Res.createInternalState Res.closeInternalState $ \resState -> do
    let openAction = open "thedb" defaultOptions { createIfMissing = True }
    db <- Res.runInternalState openAction resState

使用Snap和leveldb中的一些更改可以使这更简单:

  • 可能有一个返回Resource value的函数,而不仅仅提供假定open上下文的MonadResource函数。我正在为2.0版本进行持续调整。
  • Snap可以为MonadResourceResource monad提供支持(两个不同的概念,不幸的是名字相似)。

答案 1 :(得分:0)

Snap不需要支持MonadResource或Resource来执行此操作。你正在朝着错误的方向做monad变压器组合。看看这些类型会有所帮助。

serveSnaplet :: Config Snap AppConfig -> SnapletInit b b -> IO ()
runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a

所以你试图将IO放在ResourceT所需的位置。你应该反过来解决这个问题。使用liftIO将open "thedb" ...电话放入应用程序的初始化程序中。但open是MonadResource,因此您需要使用ResourceT实例将其转换为IO。它看起来像这样:

app = makeSnaplet "app" "An snaplet example application." Nothing $ do
    ...
    db <- liftIO $ runResourceT $ open "thedb" defaultOptions

然后将db句柄存储在App状态,稍后可以使用Handler的MonadReader或MonadState实例检索它。

相关问题