Search code examples
haskellmonad-transformershaskell-snap-frameworkleveldb

Haskell: Making Snap and LevelDB play nice


I am using the LevelDB library and Snap framework together. I have:

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

Now in my handler, I'm unsure how to get back to MonadResource IO in order to query the database:

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

Which gives me a: No instance for (MonadResource IO) arising from a use of 'get'

Any ideas? I feel like I'm missing something about how to properly create a monad "stack". Thanks


Solution

  • MonadResource/ResourceT is one way of acquiring scarce resources in a way that guarantees resources will be freed in the case of an exception. Another approach is the bracket pattern, which is supported by Snap via the bracketSnap function. You can use this to create the ResourceT context needed by LevelDB:

    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
    

    This could be made simpler with some changes in Snap and leveldb:

    • Instead of only providing the open function, which presumes a MonadResource context, there could be a function which returns a Resource value. I'm making this tweak in persistent for the 2.0 release.
    • Snap could provide support for either MonadResource or the Resource monad (two separate concepts with unfortunately similar names).