gpt4 book ai didi

haskell - 使用 `MonadBaseControl` API

转载 作者:行者123 更新时间:2023-12-04 02:26:12 25 4
gpt4 key购买 nike

我目前正在玩 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)元组,其中 bool 值指示借用的资源是否应该
被放回池中或销毁。
现在我当前的实现如下所示:

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 对。
你们对此有何看法,我该如何改进它以使其更加惯用?

最佳答案

我觉得这种方法存在根本问题。对于 StM M a 的单子(monad)等于/同构 a它会起作用的。但是对于其他 monad 来说就会有问题。让我们考虑MaybeT IO . a -> MaybeT IO (Bool, b) 类型的操作可能会失败,所以不会有Bool产生的值(value)。和代码

  void . runInIO $ do
(keep, _) <- restoreM ret :: m (Bool, b)
...

不会执行,控制流将在 restoreM 处停止.对于 ListT IO情况会更糟,如 putResourcedestroyResource将被执行多次。考虑这个示例程序,它是您的函数的简化版本:
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables, RankNTypes, TupleSections #-}
import Control.Monad
import Control.Monad.Trans.Control
import Control.Monad.Trans.List

foo :: forall m b . (MonadBaseControl IO m) => m (Bool, b) -> m b
foo act = fmap snd result
where
result :: m (Bool, b)
result = control $ \runInIO -> do
ret <- runInIO act

void . runInIO $ do
(keep, _) <- restoreM ret :: m (Bool, b)

if keep
then liftBaseWith . const $ putStrLn "return"
else liftBaseWith . const $ putStrLn "destroy"

return ret

main :: IO ()
main = void . runListT $ foo f
where
f = msum $ map (return . (, ())) [ False, True, False, True ]

它会打印
destroy
return
destroy
return

对于空列表,不会打印任何内容,这意味着不会在您的函数中调用清理。

我不得不说我不确定如何以更好的方式实现您的目标。我会尝试在签名的方向上探索
withResource :: forall m a b. (MonadBaseControl IO m)
=> Pool a -> (a -> IO () -> m b) -> m b
IO ()参数将是一个函数,该函数在执行时会使当前资源无效并将其标记为销毁。 (或者,为了更方便,将 IO () 替换为提升后的 m () )。然后在内部,因为它是 IO -基于,我只创建一个助手 MVar可以通过调用来重置
函数,最后根据值返回或销毁资源。

关于haskell - 使用 `MonadBaseControl` API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32314565/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com