Проблема с неполным вводом при использовании Attoparsec - PullRequest
7 голосов
/ 07 июня 2010

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

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

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

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

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

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

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

Ответы [ 3 ]

5 голосов
/ 08 июня 2010

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

3 голосов
/ 07 июня 2010

Я сталкивался с этой проблемой ранее, и я понимаю, что она вызвана тем, как <|> работает в определении 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 ByteString на Result возвращается parse.Это может быть своего рода хаком, но, похоже, что attoparsec-iteratee решает проблему:

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

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

0 голосов
/ 07 июня 2010

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

  • Возможно, синтаксический анализатор не осознает, что ввод сделан, и он зависит от получения EOL или получения другой записи. Следовательно, он требует частичного результата. Попробуйте накормить его эквивалентом EOL в надежде, что это заставит его.
  • Я не могу вспомнить код, но использование экземпляра Alternative может отрицательно сказаться на производительности анализа. Если это так, вы можете использовать case в комментариях и recordTypes.
  • Я использую хлопья для большого количества двоичных разборов, и это тоже очень быстро. attoparsec кажется лучше как текстовый парсер. Вы обязательно должны рассмотреть вариант.
  • Другой вариант - использовать IO на основе итераций в долгосрочной перспективе. Джон Лато сделал отличную статью об итераторах в последней статье о монаде (номер 16, мне кажется). Условие конца строки - это итерации для подачи сигнала. Остерегайтесь, однако, что типы итераторов довольно устрашающие и требуют некоторого времени для привыкания.
...