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它在IOmonad 中,并且runIdentityKProxy p => p k v k v IO rmonad 中。当然我可以readMVar进入这个代理单子,因为它是一个变压器IO,但我找不到合适的组合器。

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。但是,您的实现似乎没有达到您的预期。您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 回答