Почему между (char '') (char '') (многие charLiteral) не работает для разбора строковых литералов?

В документации для Text.Megaparsec.Char.Lexer.charLiteral предлагается использовать char '"' *> manyTill charLiteral (char '"') для разбора строковых литералов (где manyTill определено в модуле Control.Applicative.Combinators в библиотеке parser-combinators).

Однако Control.Applicative.Combinators также определяет between, который, насколько я понимаю, должен делать то же самое, что и приведенное выше предложение, когда используется так: between (char '"') (char '"') (many charLiteral).

Однако использование синтаксического анализатора between, описанного выше, не работает для синтаксического анализа строковых литералов — возникает ошибка "неожиданный конец ввода. Ожидается """ или литеральный символ" (указывающий на то, что конечная кавычка никогда не обнаруживается). Почему бы и нет?

Кроме того, в более общем плане, почему between pBegin pEnd (many p) не эквивалентно pBegin *> manyTill p pEnd?


person runeks    schedule 06.05.2020    source источник
comment
Потому что проверка парсером требует времени?   -  person Poscat    schedule 06.05.2020
comment
Дополнительное примечание: это, вероятно, будет хорошо работать в парсерах, которые возвращаются по умолчанию, то есть в основном во всех, кроме (мега) парсека.   -  person Joseph Sible-Reinstate Monica    schedule 06.05.2020
comment
@JosephSible-ReinstateMonica нет, я не думаю, что возврат может помочь вам здесь. Это было бы, если бы charLiteral на самом деле потерпел неудачу на " (но все еще потреблял символ, поэтому управление не было бы возвращено тому, что идет после many). Но в этом случае many charLiteral действительно удается — он успешно потребляет все входные данные. — Во всяком случае, megaparsec делает автоматический возврат для простых символов и строк, но не для больших комбинаторов.   -  person leftaroundabout    schedule 06.05.2020
comment
@leftaroundabout После тестирования кажется, что это более тонко, чем мы думали. Он работает, как я и ожидал, с regex-applicative и с ReadP, но не работает, как вы и ожидали, с attoparsec. Я сбит с толку, потому что думал, что attoparsec отступил, как и остальные.   -  person Joseph Sible-Reinstate Monica    schedule 06.05.2020


Ответы (1)


between l r m не делает ничего впечатляющего, он просто пытается выполнить l, затем m, затем r и возвращает результат m. Итак, в between (char '"') (char '"') (many charLiteral) many charLiteral не знает, что он не должен потреблять ". many просто продолжает потреблять все, что принимает его анализатор аргументов... что, поскольку charLiteral просто принимает все, означает, что он перебирает все до конца ввода. Второй char '"' не может остановить это, ему просто нужно обойтись тем, что осталось... т. е. провал, потому что ничего не осталось!

Напротив, manyTill на самом деле проверяет, соответствует ли «till», и только применяет каждую итерацию анализатора содержимого, когда это не так. Поэтому завершающий " не передается charLiteral, и вы получаете желаемое поведение.

person leftaroundabout    schedule 06.05.2020
comment
Спасибо. Будет ли правильно резюмировать это, сказав, что between l r (many p) и l *> manyTill p r эквивалентны, если и только если p не потребляет то, что потребляет r? - person runeks; 08.05.2020
comment
Думаю, да, но после комментариев Джозефа я больше не уверен, что понимаю, что происходит. - person leftaroundabout; 08.05.2020