В настоящее время я играю с библиотекой Bracan 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)
, где логическое значение указывает, следует ли вернуть заемный ресурс в пул или уничтожить.Работа с API `MonadBaseControl`
Теперь моя текущая реализация выглядит следующим образом:
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' дважды, что приводит к более подробному коду. Есть ли лучший способ развернуть «ret» (результат первого вызова runInIO) внутри монады IO? – bmk