Haskell 使用“MonadBaseControl”API

Haskell 使用“MonadBaseControl”API,haskell,monads,monad-transformers,Haskell,Monads,Monad Transformers,我目前正在使用Bryan O'Sullivan的库,对扩展with resource函数有疑问。 我想将with resource函数的签名从(MonadBaseControl IO m)=>池a->(a->m b)->m b更改为(MonadBaseControl IO m)=>池a->(a->m(Bool,b))->m b 我想要实现的是,操作应该返回(Bool,b)元组,其中布尔值指示借用的资源是否应该 被放回池中或销毁 现在,我当前的实现如下所示: withResource :: for

我目前正在使用Bryan O'Sullivan的库,对扩展
with resource
函数有疑问。 我想将
with resource
函数的签名从
(MonadBaseControl IO m)=>池a->(a->m b)->m b
更改为
(MonadBaseControl IO m)=>池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
withResource::对于所有m a b。(MonadBaseControl IO m)=>池a->(a->m(布尔,b))->MB
{-#专门化资源::池a->(a->IO(Bool,b))->IO b}
withResource pool act=fmap snd结果
哪里
结果::m(Bool,b)
结果=控制$\RUNIIO->掩码$\restore->do

参考资料我觉得这种方法存在一个根本问题。对于
StM ma
a
相等/同构的单子,它将起作用。但对于其他单子来说,这将是一个问题。让我们考虑<代码> MayBET IO < /代码>。
a->MaybeT IO(Bool,b)
类型的操作可能会失败,因此不会产生
Bool
值。代码在哪

  void . runInIO $ do
    (keep, _) <- restoreM ret :: m (Bool, b)
    ...
会打印出来的

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
,通过调用
函数,最后根据值返回或销毁资源。

粗略一看就可以了。有什么困扰你的?@luqui让我有点困扰的是,我必须运行
runInIO
两次,这会导致代码更加冗长。有没有更好的方法来打开IO monad中的
ret
(第一次
runInIO
调用的结果)?非常感谢您提供的有用答案。我现在可以看到“MaybeT”和“ListT”单子的问题了。。。再次感谢!
withResource :: forall m a b. (MonadBaseControl IO m)
             => Pool a -> (a -> IO () -> m b) -> m b