0

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'

何か案は?モナド「スタック」を適切に作成する方法について何かが欠けているように感じます。ありがとう

4

2 に答える 2

3

MonadResource/ResourceTは、例外が発生した場合にリソースが解放されることを保証する方法で、希少なリソースを取得する 1 つの方法です。もう 1 つのアプローチは機能bracketを介して Snap でサポートされているパターンです。これを使用して、 LevelDB が必要とするコンテキストを作成できます。bracketSnapResourceT

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 にいくつかの変更を加えることで、これをより簡単にすることができます。

  • openコンテキストを推定する関数を提供するだけでなく、MonadResourceを返す関数が存在する可能性があります。2.0 リリースに向けて、この調整を永続化します。Resource
  • MonadResourceSnap は、どちらかまたはResourceモナド (残念ながら似たような名前を持つ 2 つの別個の概念)のサポートを提供できます。
于 2014-03-04T13:13:06.893 に答える
0

Snap は、これを行うために MonadResource または Resource をサポートする必要はありません。モナドトランスフォーマーの構成を間違った方向に行っています。種類を見ると参考になります。

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

したがって、ResourceT が期待される場所に IO を配置しようとしています。これは逆にアプローチする必要があります。LiftIOopen "thedb" ...を使用して、アプリケーションの Initializer 内に呼び出しを配置し​​ます。ただしopen、MonadResource であるため、ResourceT インスタンスを使用して IO に入れる必要があります。次のようになります。

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

次に、db ハンドルを App 状態に保存すると、後でHandlerの MonadReader または MonadState インスタンスを使用して取得できます。

于 2014-03-04T17:06:38.513 に答える