Боюсь, что вы не можете использовать sepBy
здесь.
Давайте упростим это до синтаксического разбора 'a' как выборки и 'b' как новой строки. Вы собираетесь разобрать строки как
a b b a b b b c b c b c b
Так что же думает парсер при обходе такой строки? Давайте пройдем через это:
Синтаксический анализ a
или пустая последовательность
[a] b b a b b b c b c b c b
Ох, a
. Последовательность не пустая, поэтому я буду анализировать many
"bb" >> "a"
с этого момента.
a [b b a] b b b c b c b c b
Успех! Давай получим еще или закончим
a b b a [b b] b c b c b c b
Хорошо, я нашел еще bb
, поэтому последовательность продолжается. Разбор a
a b b a b b [b] c b c b c b
ваты
Проблема в том, что синтаксический анализатор не откатится, если явно не попросить сделать это .
Чтобы дать возможность отката парсера, вы должны пометить его комбинатором try
, иначе он не сможет «отменить» потребляемый ввод.
Пока что я не вижу лучшего способа, чем переписать комбинатор sepBy
, чтобы он знал, что после синтаксического анализа каждого разделителя может потребоваться вернуть его обратно в буфер, если синтаксический анализ separator >> target
завершится неудачно:
sepTry a sep = sepTry1 a sep <|> pure []
sepTry1 a sep = liftA2 (:) a (many (try $ sep *> a))
Обратите внимание, что синтаксический анализ a
должен быть включен в раздел try
- это то место, где фактически происходит сбой.
Чтобы визуализировать разницу, давайте посмотрим на тот же сценарий, но вместо sepTry
:
...
a [b b a] b b b c b c b c b
Успех! Давайте попробуем , чтобы получить еще один, если это возможно
a b b a ![b b] b c b c b c b
Хорошо, я нашел еще bb
, поэтому последовательность продолжается. Разбор a
a b b a !b b [b] c b c b c b
Не то, что я ожидал. Вернуть ошибку и переместить курсор на восклицательный знак.
a b b a ![]b b b c b c b c b
Сбой разбора bba
, последовательность разбора завершена. Разбор bbb
a b b a [b b b] c b c b c b
Успех!
В вашем случае после каждого Sample
этот синтаксический анализатор будет пытаться прочитать 2 новых строки с Sample
после них или, в случае сбоя, 3 новых строки и будет продолжать MaskedOperation
s