Функциональные парсеры: различия между версиями

Перейти к навигации Перейти к поиску
Первым преобразователем парсеров является sp. Он опускает пробелы в строке, поступающей на вход, затем применяет заданный парсер:
 
sp :: Parser Char a -> Parser Char a
sp p = p . dropWhile (== ' ')
 
или если вы предпочитаете функциональные определения:
Вторым преобразователем парсеров является just. Для данного парсера р он возвращает парсер, который делает то же, что и р, но также гарантирует, что остаток строки будет пустым. Это достигается путём применения фильтра к списку благоприятных исходов, выделяющего из него пустые остаточные строки. Поскольку остаток строки является первым элементом в списке, функция может быть определена следующим образом:
 
just :: Parser s a -> Parser s a
just p = filter (null.fst) . p
 
Упражнение 3. Дайте определение функции just, используя списки вместо функции filter.
 
infixr 5 <@
(<@) :: Parser s a -> (a -> b) -> Parser s b
(p <@ f) xs = [(ys, f v) | (ys, v) <- p xs]
 
Используя этот оператор, мы можем преобразовать парсер, распознающий цифровые символы, в парсер, возвращающий результат в виде целого числа:
 
digit :: Parser Char Int
digit = satisfy isDigit <@ f
where f c = ord c — ord '0'
 
На практике оператор <@ используется для получения некоторой величины в процессе разбора (в случае разбора компьютерной программы этой величиной может быть сгенерированный код или список всех переменных с их типами и так далее). В целом, применяя <@ мы можем добавить к парсерам семантические функции.
Мы зарезервировали слово «parser» для функции, которая возвращает все варианты разбора, сопровождаемые соответствующими им необработанными частями строк. Поэтому давайте определим новый тип для функции, которая разбирает текст, гарантирует получение пустой необработанной части строки, выбирает первое решение из списка и возвращает лишь дерево разбора (отбрасывая необработанную часть строки, поскольку известно, что она пустая на данном этапе). Функциональная программа для преобразования парсера в подобный «детерминированный синтаксический анализатор» является более лаконичной и удобочитаемой, чем определение, приведённое ранее:
 
type DetPars symbol result = [symbol] -> result
some :: Parser s a -> DetPars s a
some p = snd . head . just p
 
Используйте функцию some осторожно: эта функция предполагает наличие хотя бы одного решения, поэтому она не срабатывает в том случае, если результирующий DetPars применен к тексту, содержащему синтаксическую ошибку.
Анонимный участник

Навигация