2014-03-04 29 views
0

我一起使用LevelDB庫和Snap框架。我有:Haskell:使捕捉和LevelDB發揮不錯

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「堆棧」的內容。謝謝

回答

3

MonadResource/ResourceT是一種獲取稀缺資源的方式,保證資源在異常情況下被釋放。另一種方法是bracket模式,該模式由Snap通過the bracketSnap function支持。您可以使用它來創建通過性LevelDB需要ResourceT背景:

  • 僅提供open功能,假設一個相反:

    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 
    

    這可能與在捕捉一些變化和性LevelDB更簡單MonadResource上下文中,可能有一個函數返回Resource value。我正在對2.0版本進行持續調整。

  • Snap可以提供對MonadResourceResource monad的支持(兩個單獨的概念,但不幸有相似的名字)。
0

捕捉不需要支持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 

分貝手柄然後將其存儲在您的應用程序的狀態,你可以找回以後使用Handler的MonadReader或MonadState實例。

+0

不,這是行不通的。因爲你已經退出'runResourceT'塊,'db'會立即關閉。您提出的代碼與'withFile「foo」ReadMode return'類似。 –

+0

啊,對。我習慣於在其他情況下使用該模式,並忘記runResourceT強制清理。 – mightybyte