Leonard Wörteler leo at woerteler.de
Wed Oct 5 17:05:47 UTC 2016

```
Am 05.10.2016 um 14:32 schrieb Lian Hung Hon:
> Given
>
> data Expression = ExpToken String | ExpAnd Expression Expression
>
> How to write an attoparsec parser that parses this example:
>
> "a" and "b" and "c"
>
> into
>
> ExpAnd (ExpToken "a") (ExpAnd (ExpToken "b") (ExpToken "c"))?

You can re-implement `chainr1` from Parsec as follows:

chainr1 :: Parser a -> Parser (a -> a -> a) -> Parser a
chainr1 p op = scan
where
scan   = p >>= rest
rest x = op <*> pure x <*> scan <|> return x

Then you just plug in your parsers for variables and the `and` operator.
Working example attached.

-- Leo
-------------- next part --------------

import Data.Attoparsec.ByteString.Char8
(
Parser, parseOnly,
char8, string, anyChar, skipSpace,
manyTill, endOfInput
)
import Control.Applicative ((<|>))

data Expression
= ExpToken String
| ExpAnd Expression Expression
deriving (Eq, Show)

main :: IO ()
main = print \$ parseOnly expression "\"a\" and \"b\" and \"c\""

expression :: Parser Expression
expression = chainr1 varP andP <* skipSpace <* endOfInput

chainr1 :: Parser a -> Parser (a -> a -> a) -> Parser a
chainr1 p op = scan
where
scan   = p >>= rest
rest x = op <*> pure x <*> scan <|> return x

varP :: Parser Expression
varP = ExpToken <\$> (skipSpace *> char8 '"' *> manyTill anyChar (char8 '"'))

andP :: Parser (Expression -> Expression -> Expression)
andP = skipSpace *> string "and" *> pure ExpAnd
```