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

Haskell的EitherT如今被什么替代?旧博客相关技术问询

嘿,这个问题挺有意思的——刚好我也翻看过Gabriel那篇2012年的旧博客,用EitherT实现循环中断的思路确实巧妙,但这些年Haskell生态的错误处理方案已经标准化了,下面给你梳理下现在的替代选项:

替代EitherT实现循环中断的现代方案

1. 标准库ExceptT(首选替代)

首先明确:旧的EitherT包被废弃,核心原因是它的功能完全被标准库的ExceptT覆盖了——ExceptT一开始在transformers包中,后来直接并入了GHC base库,成为官方推荐的错误处理monad transformer。

它和旧EitherT的语义几乎完全一致,只是命名更贴合“异常处理”的语境,把left换成了throwE,runEitherT换成了runExceptT。针对你贴的博客代码,改写后的版本是:

import Control.Monad.Trans.Except
import Control.Monad (forever, when)
import Control.Monad.IO.Class (liftIO)

exit :: ExceptT () IO ()
exit = throwE ()

main :: IO ()
main = do
  _ <- runExceptT $ forever $ do
    str <- liftIO getLine
    when (str == "exit") exit
  return ()

至于你提到的ErrorT的问题,确实存在:旧版ErrorT依赖Error类型类,语义模糊(会自动把错误值包装成Maybe或其他类型),而ExceptT直接基于Either的清晰语义,没有这些历史包袱,是现在错误处理的标准选择。

2. Gabriel自己的Control.Break(更简洁的专用方案)

你也提到了Gabriel的Control.Break包,这其实是他后来专门为循环中断场景设计的方案——完全避开了用错误处理monad transformer来模拟控制流的“hack”感,代码更直观,也比ContT轻量太多(ContT是处理续延的通用工具,用来做循环中断确实大材小用)。

用Control.Break实现同样的功能,代码会更简洁:

import Control.Break

main :: IO ()
main = breakLoop $ do
  str <- liftIO getLine
  when (str == "exit") break

这个方案把循环中断的逻辑直接封装起来,不需要借助错误处理的语义,可读性和维护性都更好。

补充:为什么EitherT被废弃?

本质上是生态标准化的结果:EitherT和ExceptT的功能几乎完全重合,但ExceptT后来成为了官方标准实现,维护更稳定、生态支持更广泛,所以旧的EitherT包就被标记为废弃,引导用户转向标准方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:47:51