Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsec negative match

Tags:

haskell

parsec

parseIdent :: Parser (String)
parseIdent = do
  x <- lookAhead $ try $ many1 (choice [alphaNum])
  void $ optional endOfLine <|> eof
  case x of
    "macro" -> fail "illegal"
    _ -> pure x

I'm trying to parse an alphanumeric string that only succeeds if it does not match a predetermined value (macro in this case).


However the following is giving me an error of:

*** Exception: Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string.

Which does not make sense, how does many1 (choice [alphaNum]) accept an empty string?


This error goes away if i remove the lookAhead $ try. But it 'fails' with illegal:

...
*** Exception: (line 6, column 36):
unexpected " "
expecting letter or digit or new-line
illegal

Am I going about this correctly? Or is there another technique to implement a negative search?

like image 339
Chris Stryczynski Avatar asked May 13 '26 05:05

Chris Stryczynski


1 Answers

You almost have it:

import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.String
import Control.Monad

parseIdent :: Parser (String)
parseIdent = try $ do
  x <- many1 alphaNum
  void $ optional endOfLine <|> eof
  case x of
    "macro" -> fail "illegal"
    _ -> pure x

So, why didn't your code work?

  • the try is in the wrong spot. The real backtracking piece here is backtracking after you've gotten back your alphanumeric word and checked it isn't "macro"
  • lookAhead has no business here. If you end up with the word you wanted, you do want the word to be consumed from the input. try already takes care of resetting your input stream to its previous state
like image 100
Alec Avatar answered May 15 '26 05:05

Alec



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!