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
相关产品推荐
相关产品推荐

