Чтобы выделить левую рекурсию в этом:
foo ::= alphanum
| foo "." alphanum
| alphanum "(" foo ")"
Вы можете начать с переписывания этого:
foo ::= alphanum ("(" foo ")")?
| foo "." alphanum
Затем вы можете выделить левую рекурсию, используя стандартный прием замены:
x ::= x y | z
С:
x ::= z x'
x' ::= y x' | ∅
Другими словами:
x ::= z y*
С x
= foo
, y
= "." alphanum
и z
= alphanum ("(" foo ")")?
, что становится:
foo ::= alphanum ("(" foo ")")? ("." alphanum)*
Тогда я считаю, что ваш парсер может быть примерно таким, поскольку ?
~ ноль или единица ~ Maybe
~ optional
и *
~ ноль или более ~ []
~ many
:
parser = do
prefix <- Simple <$> alphanum
maybeParens <- optional (constant "(" *> parser <* constant ")")
suffixes <- many (constant "." *> alphanum)
let
prefix' = case maybeParens of
Just content -> Paren prefix content
Nothing -> prefix
pure $ foldl' Dotted prefix' suffixes