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 []
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