Avec parsec, comment puis-je parse zéro ou plus foo1 terminée par foo2 et tous séparés par point?

StackOverflow https://stackoverflow.com/questions/2373897

  •  24-09-2019
  •  | 
  •  

Question

Ce que je suis en train de faire semble assez simple, mais comme je suis un newb parsec Haskell, la solution est me éludant.

J'ai deux parseurs, disons foo1 et foo2foo1 peut analyser un terme intermedate et foo2 parse un terme fin. Les termes sont séparés par un symbole, ".".

Les phrases que je dois analyser sont

  • foo2
  • foo1.foo2
  • foo1.foo1.foo2

et ainsi de suite.

Ma pensée originale était de faire

do k <- sepBy foo1 (char'.')
   j <- foo2

mais ce ne serait pas attraper le cas de foo2 seule.

Était-ce utile?

La solution

Vous voulez endBy, pas sepBy.

foo = do k <- foo1 `endBy` char '.'
         j <- foo2
         ... 

Cela forcera le séparateur à être présente après chaque occurrence de foo1.

Bien sûr, endBy est trivialement remplaçable par many, qui peut être plus clair.

foo = do k <- many $ foo1 <* char '.' 
         j <- foo2
         ...

ou, sans Control.Applicative:

foo = do k <- many $ do x <- foo1; char '.'; return x
         j <- foo2
         ...

Autres conseils

D'abord, vous voulez endBy au lieu de sepBy:

do k <- endBy foo1 (char'.')
   j <- foo2

En second lieu, il serait

  

attraper le cas juste foo2

De documentation :

  

Parsis de endBy p sep zéro ou plusieurs occurrences de p, séparés par sep. Renvoie la liste des valeurs renvoyées par p.

Essayez quelque chose comme

many (foo1 >>= (\v -> char '.' >> return v)) >>= \v1 ->
  foo2 >>= \v2 ->
  -- ...
  -- combine v1 & v2 somehow

(Juste un croquis, bien sûr.)

En général, le combinateur many est l'équivalent de parsec Kleene étoiles ; et si vous allez ajouter quelque chose de simple comme un point de fuite à un analyseur existant, en utilisant >> / >>= peut effectivement être plus propre et plus simple que d'utiliser la notation do.

Bien sûr, il attraperait le cas de foo2. L'utilisation de votre foo1, la parole de Leiden:

let a = sepBy word (char '.')
parseTest a "foo.bar.baz"
parseTest a "foo"
parseTest a ".baz"
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top