Проблема с неполным вводом при использовании attoParsec

StackOverflow https://stackoverflow.com/questions/2988988

  •  24-10-2019
  •  | 
  •  

Вопрос

Я преобразую какой -нибудь функционирующий код Haskell, который использует ParSec, чтобы вместо этого использовать AttoParsec в надежде получить лучшую производительность. Я внес изменения и все компилизируется, но мой анализатор работает неправильно.

Я анализирую файл, который состоит из различных типов записей, по одному на строку. Каждая из моих отдельных функций для анализа записи или комментария работает правильно, но когда я пытаюсь написать функцию, чтобы скомпилировать последовательность записей, анализатор всегда возвращает частичный результат, потому что он ожидает большего ввода.

Это два основных вариации, которые я пробовал. Оба имеют одинаковую проблему.

items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine

Для этого второго я изменил анализаторы записи/комментариев, чтобы потреблять символов конца линии.

items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput

Есть ли что -нибудь не так с моим подходом? Есть ли другой способ достичь того, что я пытаюсь?

Это было полезно?

Решение

Я сталкивался с этой проблемой раньше, и я понимаю, что это вызвано тем, как <|> работает в определении sepBy:

sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
    where scan = liftA2 (:) p ((s *> scan) <|> pure [])

Это только перейдет к pure [] однажды (s *> scan) не удалось, что не произойдет только потому, что вы находитесь в конце ввода.

Мое решение было просто позвонить feed с empty Отсутствие на Result возвращен parse. Анкет Это может быть своего рода взлом, но, похоже, это также, как attoparsec-iteratee имеет дело с проблемой:

f k (EOF Nothing)  = finalChunk $ feed (k S.empty) S.empty

Насколько я могу судить, это единственная причина, по которой attoparsec-iteratee Работает здесь и простым старым parse не.

Другие советы

Если вы пишете анализатор AttoParsec, который потребляет как можно больше ввода перед сбоем, вы должны сообщить о продолжении частичного результата, когда вы достигнете конца вашего ввода.

Вы даете довольно мало информации, поэтому я думаю, что трудно оказать вам хорошую помощь. Однако есть несколько комментариев, которые я хотел бы дать:

  • Возможно, анализатор не понимает, что ввод сделан, и он зависит от получения EOL или получения другой записи. Следовательно, это запрашивает частичный результат. Попробуйте кормить его эквивалентом EOL в надежде, что он его насильно.
  • Я не могу вспомнить код, но использование альтернативного экземпляра может нанести ущерб производительности. Если это так, вы можете захотеть принять участие в комментариях и записи.
  • Я использую хлопья для большого бинарного анализа, и это также очень быстро. AttoParsec кажется лучше, как текстовый, хотя. Вы обязательно должны рассмотреть этот вариант.
  • Другим вариантом является использование IO на основе ITERATE в более длительном заезде. Джон Лато сделал отличную статью о Iterates в последнем читателе Monad (я считаю, что выпуск № 16). Условием конец линии является итерационным сигналом. Остерегайтесь, хотя типы итерации довольно пугающие и требуют некоторого времени, к которым привыкают.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top