我目前正在玩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)
元組,其中布爾值指示借用資源應將 放回池中還是銷燬。現在使用`MonadBaseControl` API
我當前的實現看起來是這樣的:
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
@luqui困擾我一點的是,我必須運行'runInIO'兩次,這導致了更冗長的代碼。有沒有更好的方法來打開IO monad內部的'ret'(第一個'runInIO'調用的結果)? – bmk