Home > Enterprise >  Conditions in Parsec
Conditions in Parsec

Time:12-12

If I have a parser than reads a string of numbers separated by spaces into a list of Ints, how do I handle a trailing space? At the moment I have:

row :: Parser [Int]
row  = do
  optional spaces
  f <- (many (oneOf "0123456789"))
  r <- ((char ' ') >> row) <|> pure []
  pure (read f:r)

Which works fine with a string that does not have a trailing space but fails with a trailing space.

>λ= parse row "" " 2  0 12  3     7"
Right [2,0,12,3,7]

>λ= parse row "" " 2  0 12  3     7  "
Right [2,0,12,3,7,*** Exception: Prelude.read: no parse

What is the solution to this problem and more so, how would I have a condition where if '\n' is consumed then the parser returns []

EDIT: From reading @amalloy's answer and the parsec source code, I thought it useful to add a version that works here (although, @amalloy's advice to not try and roll existing functions makes more sense)

row :: Parser [Int]
row = do
  spaces
  f <- (read <$> many1 digit)
  do
    many1 $ char ' '
    r <- row
    pure (f:r) <|> pure [x]
  <|> pure []

CodePudding user response:

Instead of implementing all this low-level stuff yourself, I suggest just using sepEndBy. For example,

row :: Parser [Int]
row = spaces *> (int `sepEndBy` many1 space)
  where int = read <$> many1 digit
  • Related