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

Haskell optparse-applicative是否可在OP.Parser中添加月份范围联动校验

解决方案

你完全可以直接在OP.Parser中完成该校验,无需等到解析完成后手动调用parserFailure实现。

方案1:使用官方内置check组合子(推荐)

optparse-applicative专门提供了check组合子,用于给已解析的结果附加自定义校验规则,修改后的代码如下:

import qualified Options.Applicative as OP

type Month = Int

parseMonths :: OP.Parser (Month, Month)
parseMonths = OP.check validateRange rawMonthParser
  where
    rawMonthParser = liftA2 (,)
        (OP.option
            (OP.eitherReader $
             parseNumber "month" (\n -> 1<=n && n<=12) "month")
            (OP.metavar "MONTH" <>
             OP.long "from-month" <>
             OP.value 1))
        (OP.option
            (OP.eitherReader $
             parseNumber "month" (\n -> 1<=n && n<=12) "month")
            (OP.metavar "MONTH" <>
             OP.long "to-month" <>
             OP.value 12))
    validateRange (fromMonth, toMonth)
      | fromMonth <= toMonth = Success ()
      | otherwise = Error "起始月份不能晚于结束月份,请调整--from-month和--to-month的取值"

方案2:兼容旧版本实现

如果使用的optparse-applicative版本较旧没有check,也可以利用Parser的Monad实例手动实现校验:

parseMonths :: OP.Parser (Month, Month)
parseMonths = do
  fromMonth <- OP.option
      (OP.eitherReader $ parseNumber "month" (\n -> 1<=n && n<=12) "month")
      (OP.metavar "MONTH" <> OP.long "from-month" <> OP.value 1)
  toMonth <- OP.option
      (OP.eitherReader $ parseNumber "month" (\n -> 1<=n && n<=12) "month")
      (OP.metavar "MONTH" <> OP.long "to-month" <> OP.value 12)
  if fromMonth <= toMonth
    then pure (fromMonth, toMonth)
    else fail "起始月份不能晚于结束月份,请调整--from-month和--to-month的取值"

以上两种方式的错误信息都会和optparse内置的参数校验错误走相同的输出逻辑,格式统一,不需要手动处理错误返回流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 02:06:02