【发布时间】:2015-08-31 15:17:25
【问题描述】:
我目前正在使用 Bryan O'Sullivan 的 resource-pool 库,并且对扩展 withResource 函数有疑问。
我想将withResource 函数的签名从(MonadBaseControl IO m) => Pool a -> (a -> m b) -> m b 更改为(MonadBaseControl IO m) => Pool a -> (a -> m (Bool, b)) -> m b。
我想要实现的是,该操作应该返回(Bool, b) 元组,其中布尔值指示借用的资源是否应该
放回池中或销毁。
现在我当前的实现如下所示:
withResource :: forall m a b. (MonadBaseControl IO m) => Pool a -> (a -> m (Bool, b)) -> m b
{-# SPECIALIZE withResource :: Pool a -> (a -> IO (Bool,b)) -> IO b #-}
withResource pool act = fmap snd result
where
result :: m (Bool, b)
result = control $ \runInIO -> mask $ \restore -> do
resource <- takeResource pool
ret <- restore (runInIO (act resource)) `onException`
destroyResource pool resource
void . runInIO $ do
(keep, _) <- restoreM ret :: m (Bool, b)
if keep
then liftBaseWith . const $ putResource pool resource
else liftBaseWith . const $ destroyResource pool resource
return ret
而且我有一种感觉,这不是它应该看起来的样子......
也许我没有正确使用MonadBaseControl API。
你们如何看待这个问题,我该如何改进它以使其更加地道?
【问题讨论】:
-
粗略一瞥看起来不错。你有什么困扰?
-
@luqui 让我有点困扰的是,我必须运行两次
runInIO,这会导致代码更加冗长。有没有更好的方法来解开 IO monad 中的ret(第一个runInIO调用的结果)?
标签: haskell monads monad-transformers