我正在使用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;的内容。感谢
答案 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版本进行持续调整。MonadResource
或Resource
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实例检索它。