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

如何通过包装ExceptT的newtype合理实现MonadError?

问题解答

你的需求是可以实现的,核心思路是把BlahT内部的ExceptT拆解出来,针对底层m的错误进行捕获处理,而ExceptT自身返回的Left值视为正常结果不干预。

完整的实现代码如下:

import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
import Control.Monad.Error.Class (MonadError(..))

newtype BlahT e m a = BlahT (ExceptT e m a) deriving newtype (Functor, Applicative, Monad)

instance MonadError e m => MonadError e (BlahT e' m) where
  throwError = BlahT . ExceptT . fmap Right . throwError
  catchError (BlahT et) handler = BlahT . ExceptT $
    catchError (runExceptT et) (runExceptT . handler)

实现说明

  1. throwError的实现:你原来的写法是正确的——把底层m抛出的错误e,转换成m (Either e' a)类型(用Right包裹错误对应的结果),再逐层包装成ExceptT和BlahT。
  2. catchError的实现:
    • 先拆解BlahT得到内部的ExceptT et,通过runExceptT et拿到底层m的计算结果m (Either e' a)。
    • 对这个m计算使用底层的catchError:如果m在运行过程中抛出了e类型的错误,就调用传入的handler e得到BlahT类型的结果,再通过runExceptT转换成m (Either e' a);如果m正常运行完成(不管返回的是Left e'还是Right a),则直接保留原结果。
    • 最后把处理后的m (Either e' a)重新包装成ExceptT和BlahT,返回符合类型要求的结果。

这样就完全符合你的需求:只有底层m抛出错误时才触发catchError的处理逻辑,ExceptT自身返回的Left值会被直接保留,不会被catchError干预。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 00:20:38