Пост ниже является литературным кодом - его можно скопировать в файл и загрузить в интерпретатор.
>-- |ParsersFunc.hs
>-- Реализация комбинаторов синтаксического разбора наиболее конкретным образом.
>module ParsersFunc where
Синтаксический разбор - это извлечение структуры предложения из строки. Или "извлечение структуры текста из его
(
Read more... )
Comments 16
(The comment has been removed)
Reply
(The comment has been removed)
По сути, применение всех a->b снаружи эквивалентно изначальной задаче парсинга. А именно, вместо высказывания "many (char 'a' or char 'b')" нам придется сказать "many (any char) such that every char == 'a' or == 'b'". Иными словами, "возьмем изначальную строку целиком и построим из нее нужню нам структуру с нуля". Т.е. свели задачу к изначальной. На данной грамматике функция построения нужной структуры простая - проверим условие на каждом символе, если на всех срослось, то изначальная строка и есть нужная нам структура. Обычно же это далеко не так...
Запихивание функций в разборщик позволяет декомпозицию. В разборщик мы суем простые функции, грамматику выражаем в сравнительно простых высказываниях, а на выходе получаем сложную структуру.
Reply
(The comment has been removed)
Reply
*Main> parse "/a/b/" (pure (\(_,s,_)->s) <*> check (\(x,_,y)->x==y) (pure (\l s r->(l,s,r)) <*> item <*> (many item) <*> item))
Right "a/b"
(Возможность разделителю содержаться в середине оставлена намеренно.) Я правильно понимаю, что на имеющихся комбинаторах проще не получится, чтобы сделать проще, нужна уже операция над a->Parser b, что и отличает монаду от аппликативного функтора?
Соответственно, если хочется добиться того, чтобы в середине не содержалось разделителя, то это уже запихивает половину парсера в аргумент check (\(x,s,y)->x==y && not elem x s)?
Reply
Монады в ближайшем будущем. ;)
Reply
Reply
Reply
Я бы сказал, что она не столько жадная, сколько тупая, как пробка. В частности, она не найдет полный парсинг, если так случилось, что он оказался в списке не первым. Какой бы пример подобрать, чтобы и перестановка альтернатив не помогала?.. Ну вот, например: нам годится строка, начинающаяся с одиночного a, за которым следует серия b, или строка, начинающаяся с нескольких a, за которыми следует одиночный b:
*Main> parse "abb" (pure (\s c->s++[c]) <*> many (char 'a') <*> char 'b' <|> pure (:) <*> char 'a' <*> many (char 'b'))
Left "error somewhere there: b"
*Main> parse "aab" (pure (\s c->s++[c]) <*> many (char 'a') <*> char 'b' <|> pure (:) <*> char 'a' <*> many (char 'b'))
Right "aab"
а при перестановке альтернатив - ситуация обратная:
*Main> parse "abb" (pure (:) <*> char 'a' <*> many (char 'b') <|> pure (\s c->s++[c]) <*> many (char 'a') <*> char 'b')
Right "abb"
*Main> parse "aab" (pure (:) <*> char 'a' <*> many (char 'b') <|> pure (\s c->s++[c]) <*> many ( ( ... )
Reply
Надо сделать примерно вот так:
parse text parser = let r = parser text in case (filter (not . null . snd) r,r) of
([],[]) -> Left "no parse"
([],(_,rem):_) -> Left $ "error somewhere here: "++take 20 rem++"..."
((a,_):_,_) -> Right a(код не тестировал)
Но это и сложнее объяснять, и редко встречается.
Reply
Reply
Leave a comment