[Haskell-cafe] Recursive attoparsec

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 --------------
{-# LANGUAGE OverloadedStrings #-}

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


More information about the Haskell-Cafe mailing list