You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中如何忽略释放资源函数异常?优先抛出核心动作原异常

解决方案

标准Haskell base库中没有直接提供满足你需求的现成函数,但你可以基于bracket和异常处理逻辑自定义一个函数,确保核心动作抛出的原始异常被优先保留,同时保证资源释放操作总能执行。

自定义实现示例

基于base库的版本

import Control.Exception (SomeException, mask, catch, onException)

bracketPreserveActionException :: IO a -> (a -> IO ()) -> (a -> IO b) -> IO b
bracketPreserveActionException acquire release act = mask $ \restore -> do
  resource <- acquire
  -- 执行核心动作,若抛出异常则执行释放操作并忽略释放的异常
  result <- restore (act resource)
    `onException` (release resource `catch` \(_ :: SomeException) -> return ())
  -- 核心动作成功时,正常执行释放操作(此时释放异常会被抛出)
  release resource
  return result

基于UnliftIO库的版本(适配你的示例代码)

import UnliftIO.Exception (SomeException, mask, catch, onException)
import UnliftIO (MonadUnliftIO, withRunInIO)

bracketPreserveActionException :: MonadUnliftIO m => m a -> (a -> m ()) -> (a -> m b) -> m b
bracketPreserveActionException acquire release act = withRunInIO $ \run ->
  mask $ \restore -> do
    resource <- run acquire
    result <- restore (run $ act resource)
      `onException` (run (release resource) `catch` \(_ :: SomeException) -> return ())
    run $ release resource
    return result

逻辑说明

  • 当核心动作act抛出异常时,函数会执行资源释放操作release,但捕获并忽略释放过程中产生的任何异常,从而保留核心动作的原始异常。
  • 当核心动作成功完成时,函数正常执行释放操作,若此时释放过程抛出异常,该异常会被正常抛出(因为此时核心动作已成功,释放失败属于需要关注的错误)。

为什么原生bracket不符合需求

原生bracket的行为是:如果核心动作抛出异常,执行释放操作后,若释放操作也抛出异常,释放的异常会覆盖核心动作的原始异常,这正是你遇到的核心问题——SQL事务中止后,释放操作的错误掩盖了核心SQL操作的原始错误。

内容的提问来源于stack exchange,提问作者Saurabh Nanda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 02:57:13