Вместо sepBy
такие проблемы часто могут быть решены с помощью manyTill
, хитрый момент заключается в том, чтобы сохранить входные данные, которые не потребляются manyTill
, для этого нужно использовать try $ lookAhead
Примечание: причину можно найти в исходном коде Parsec
.Внутренне manyTill
использует <|>
, поэтому try
вступает в силу, а lookAhead
может сохранять ввод при применении монадного связывания >>=
, >>
Итак, коррекциявыглядеть так:
parseBlock = between
(char '{' >> spaces)
(spaces >> char '}')
(do
stmts <- manyTill (parseStmt <* spaces)
(try $ lookAhead (parseExpr >> space))
parseExpr
)
Приведенный выше парсер просто возвращает вывод parseExpr
, то есть 5
, если это ваше намерение, его можно упростить с помощью:
manyTill (parseStmt <* spaces) (try $ lookAhead (parseExpr >> space)) >> parseExpr
если вам действительно нужна разобранная строка операторов, она становится:
(do
stmts <- manyTill (parseStmt <* spaces)
(try $ lookAhead (parseExpr >> space))
expr <- parseExpr
return (concat (stmts ++ [expr]))
)
и возвращает 555