4

パッケージのControl.Proxyチュートリアルではpipes-3.1.0、作成者は次の機能を提供します。

cache :: (Proxy p, Ord key) => key -> p key val key val IO r
cache = runIdentityK (loop M.empty) where
    loop _map key = case M.lookup key _map of
        Nothing -> do
            val  <- request key
            key2 <- respond val
            loop (M.insert key val _map) key2
        Just val -> do
            lift $ putStrLn "Used cache!"
            key2 <- respond val
            loop _map key2

同時アプリケーションキャッシングリクエストが欲しいので、次のデータ型があります

newtype Cache k v = Cache (MVar (M.Map k v))

そして今、私cacheは署名付きの新しい関数が欲しい

cache :: (Proxy p, Ord k) => Cache k v -> k -> p k v k v IO r
cache (Cache c) k = readMVar c >>= \m -> runIdentityK $ loop m k
    where loop m key = case M.lookup key m of
            Nothing -> do
                val <- request key
                respond val >>= loop (M.insert key val m)
            Just val -> respond val >>= loop m

ただし、これはモナドにあり、readMVarモナドにあるため、タイプチェックに失敗します。トランスフォーマーなので、確かにこのプロキシモナドに持ち上げることはできますが、適切なコンビネータを見つけることができません。IOrunIdentityKProxy p => p k v k v IO rreadMVarIO

4

2 に答える 2

5

解決策は簡単でしたlift。以前から使おうと思っていたのですが、どうやら努力が足りなかったようです。これは、私の目的の大まかなタイプチェックバージョンですcache

cache = runIdentityK . loop
    where loop (Cache c) key = lift (takeMVar c) >>= \m -> case M.lookup key m of
            Nothing -> do
                val <- request key
                lift . putMVar c $ M.insert key val m
                respond val >>= loop (Cache c)
            Just val -> do
               lift $ putMVar c m 
               respond val >>= loop (Cache c)
于 2013-02-06T15:07:24.983 に答える
3

を追加するのと同じくらい簡単liftです。ただし、実装が意図したとおりに機能していないようです。最初に 1 回だけ読み取り、MVarその後は二度と使用しません。更新されたマップをループ内で渡すだけです。異なるスレッドが を通じて変更を確認する必要があるMVar場合は、それも更新する必要があります。提案(コンパイルされますが、それがどのように機能するかはテストしていません):

cache :: (Proxy p, Ord k) => Cache k v -> k -> p k v k v IO r
cache (Cache c) k = runIdentityK loop k
    where 
      loop key = do
        m <- lift (readMVar c)
        case M.lookup key m of
            Nothing -> do
                val <- request key
                lift $ modifyMVar_ c (return . M.insert key val)
                respond val >>= loop
            Just val -> respond val >>= loop
于 2013-02-06T15:12:02.487 に答える