Haskell - перемежать парсер другим - PullRequest
1 голос
/ 07 февраля 2020

У меня есть два синтаксических анализатора parser1 :: Parser a и parser2 :: Parser a.

Теперь я хотел бы проанализировать список a s с добавлением их parser2

Требуемая подпись что-то вроде

interspersedParser :: Parser b -> Parser a -> Parser [a]

Например, если Parser a анализирует символ 'a' и Parser b анализирует символ 'b', тогда interspersedParser должен проанализировать

""
"a"
"aba"
"ababa"
...

Я использую мегапарсек c. Уже есть какой-нибудь комбинатор, который ведет себя так, которого я сейчас не могу найти?

Ответы [ 2 ]

3 голосов
/ 07 февраля 2020

Конечно, вы можете использовать sepBy, но это не просто:

interspersedParser sepP thingP = (:) <$> thingP <*> many (sepP *> thingP)

РЕДАКТИРОВАТЬ: О, это требует по крайней мере одну вещь, чтобы быть там. Вы также хотели пусто, поэтому просто вставьте <|> pure [] в конце.

На самом деле, это, как правило, sepBy1 (вариант sepBy, требующий хотя бы одного):

-- | @sepBy p sep@ parses /zero/ or more occurrences of @p@, separated
-- by @sep@. Returns a list of values returned by @p@.
--
-- > commaSep p = p `sepBy` comma

sepBy :: Alternative m => m a -> m sep -> m [a]
sepBy p sep = sepBy1 p sep <|> pure []
{-# INLINE sepBy #-}

-- | @sepBy1 p sep@ parses /one/ or more occurrences of @p@, separated
-- by @sep@. Returns a list of values returned by @p@.

sepBy1 :: Alternative m => m a -> m sep -> m [a]
sepBy1 p sep = (:) <$> p <*> many (sep *> p)
{-# INLINE sepBy1 #-}
3 голосов
/ 07 февраля 2020

В парсе c есть парсер sepBy, который это делает. Похоже, тот же парсер доступен и в мегапарсе c: https://hackage.haskell.org/package/megaparsec-4.4.0/docs/Text-Megaparsec-Combinator.html

...