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

Parsers库中避免使用fail函数:Trifecta示例替代方案问询

Replacing fail in Trifecta Parsers

Great question! You’re totally right that using fail isn’t recommended in Trifecta (or modern Haskell parsing libraries overall) — it relies on the MonadFail typeclass, which is being phased out because it hides error handling logic and produces unclear error messages. Let’s break down the best ways to rewrite your parserNaturalNoLeadZero without fail:

Option 1: Use unexpected for Clear Error Messages

Trifecta provides the unexpected function to explicitly signal invalid input with a custom message. This is straightforward and integrates cleanly with Trifecta’s built-in error reporting:

import Text.Trifecta

parserNaturalNoLeadZero :: Parser Integer
parserNaturalNoLeadZero = do
  digits <- some digit
  if length digits > 1 && head digits == '0'
    then unexpected "leading zero in natural number"
    else return $ read digits

Option 2: Use guard with <?> for Concise Checks

If you prefer more compact code, combine guard (from Control.Monad) with <?> to attach a custom error message when the guard fails:

import Text.Trifecta
import Control.Monad (guard)

parserNaturalNoLeadZero :: Parser Integer
parserNaturalNoLeadZero = do
  digits <- some digit
  guard $ not (length digits > 1 && head digits == '0') <?> "Leading Zeros"
  return $ read digits

The <?> operator lets you override the default error message, making it clear exactly why the parse failed.

Option 3: Rewrite with Parser Combinators (Most Idiomatic)

For a more idiomatic parser design, avoid conditional checks entirely by defining valid input patterns directly with combinators. This makes your parser’s intent clearer and avoids explicit failure logic:

import Text.Trifecta

parserNaturalNoLeadZero :: Parser Integer
parserNaturalNoLeadZero = (singleDigit <|> multiDigitNoLeadingZero) >>= return . read
  where
    singleDigit = some digit  -- Matches any single digit (0-9)
    multiDigitNoLeadingZero = do
      firstDigit <- satisfy (/= '0')  -- First digit can't be zero
      restDigits <- many digit       -- Followed by any number of digits
      return $ firstDigit : restDigits

This approach describes exactly what counts as valid input, so the parser only succeeds when the input fits the pattern — no need to check for invalid cases after the fact.

Why These Are Better Than fail

  • Explicitness: All these options make error handling intentional, so anyone reading your code can see exactly when and why a parse might fail.
  • Better Error Reporting: Trifecta’s built-in functions like unexpected and <?> produce more helpful error messages than fail, which just uses a generic string.
  • Future-Proof: These methods rely on Trifecta’s core, stable features, whereas MonadFail (and thus fail for parsers) is being deprecated in favor of more robust error handling.

内容的提问来源于stack exchange,提问作者Răzvan Flavius Panda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:43:43