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

Haskell Monadic解析器开发中如何为相关函数添加错误处理

解决方案

你当前的核心问题是修改了addop/mulop的返回类型后,原有的chainl1没有对Either的错误分支做处理,两种实现方案如下:

方案1:适配你当前的修改,手动处理Either分支

你需要同步修改chainl1、term'、expr'的签名和实现,在解析运算符时判断是否返回错误:

-- 修改chainl1签名和实现,兼容返回Either的运算符
chainl1 :: Parser a -> Parser (Either String (a -> a -> a)) -> Parser (Either String a)
chainl1 p op = do
  firstVal <- p
  rest firstVal
  where
    rest a = (do
      opRes <- op
      case opRes of
        -- 遇到错误直接向上返回
        Left err -> pure $ Left err
        Right f -> do
          b <- p
          rest (f a b)
      ) <|> pure (Right a)

-- 同步修改expr'和term'的签名,返回可能携带错误的解析结果
expr'::Parser (Either String Double)
expr' = term' `chainl1` addop

term'::Parser (Either String Double)
term' = factor' `chainl1` mulop

修改完成后,addop/mulop返回的Left "错误信息"会一路传递到expr'的返回值中,你可以在解析的最终入口处统一处理错误。


方案2(更推荐):把错误能力整合到Parser Monad中

Haskell的Monad特性天然支持错误短停逻辑,不需要手动嵌套Either到返回值里:

  1. 如果你是自定义Parser,直接把Parser的底层定义改成支持错误的形式:
    newtype Parser a = Parser { runParser :: String -> Either String (a, String) }
    
    为Parser实现Monad实例时,只要某一步返回Left,后续所有步骤都会跳过,直接向上传递错误。
  2. 把addop/mulop的签名改回原来的Parser (Double -> Double -> Double),遇到错误时直接调用Parser Monad的fail方法抛出错误即可:
    addop = do
      -- 匹配运算符失败的逻辑
      fail "无效的加减运算符"
    

这种方案不需要修改原有chainl1的实现,代码更简洁,也更符合Haskell的惯用写法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 04:45:03