Skip to content

Haskell Parser Combinators Guide — Parsec, Attoparsec, and Megaparsec

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Haskell Parser Combinators Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Haskell parser combinators like Parsec build modular parsers from small primitive parsers using combinators -- (<|>) for choice, many for zero-or-more, and token for character matching -- with Attoparsec for high-performance streaming and Megaparsec for excellent error messages.

Basic Parsec

import Text.Parsec
import Text.Parsec.String (Parser)

-- Parse a single digit
digit :: Parser Char
digit = oneOf "0123456789"

-- Parse a number (one or more digits)
number :: Parser Int
number = do
    digits <- many1 digit
    return $ read digits

-- Parse addition
addition :: Parser Int
addition = do
    x <- number
    spaces
    char '+'
    spaces
    y <- number
    return $ x + y

Combinators

-- Choice: (<|>) tries first, if fails tries second
color :: Parser String
color = string "red" <|> string "green" <|> string "blue"

-- Repetition
many p    -- zero or more
many1 p   -- one or more
optional p -- zero or one

-- Between
-- between open close p parses p between open and close
parens = between (char '(') (char ')')
braces = between (char '{') (char '}')

-- Example: (123)
parsed = parse (parens number) "" "(123)"

Expression Parsing

import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.Token

expr :: Parser Int
expr = buildExpressionParser operators term

operators = [
    [Prefix (char '-' >> return negate)],
    [Infix (char '*' >> return (*)) AssocLeft,
     Infix (char '/' >> return div) AssocLeft],
    [Infix (char '+' >> return (+)) AssocLeft,
     Infix (char '-' >> return (-)) AssocLeft]
    ]

term :: Parser Int
term = number <|> parens expr

-- Usage: parse expr "" "2+3*4" = Right 14

JSON Parser Example

{-# LANGUAGE OverloadedStrings #-}
import Data.Attoparsec.Text
import Data.Text (Text)

jsonValue :: Parser Value
jsonValue = object <|> array <|> string' <|> number' <|> bool <|> null'

object = do
    char '{'
    pairs <- sepBy pair (char ',')
    char '}'
    return $ Object pairs

pair = do
    key <- stringLiteral
    char ':'
    val <- jsonValue
    return (key, val)

array = between (char '[') (char ']') $
    sepBy jsonValue (char ',')

Common Mistakes

1. Left Recursion

expr = expr <|> term never terminates. Use chainl1 or buildExpressionParser with proper associativity.

2. Not handling whitespace

Always parse optional whitespace between tokens: lexeme, spaces, or pipe through a token layer.

3. Overlapping choices

string "if" <|> string "ifx" never matches "ifx" because "if" succeeds first. Order choices from most specific.

Practice Questions

1. What does (<|>) do in parsing? Choice combinator: try the first parser, if it fails try the second. Like alternation in grammars.

2. What is the difference between many and many1? many p matches zero or more occurrences (always succeeds). many1 p requires at least one match.

3. How do you handle operator precedence? Use buildExpressionParser with a table of operators grouped by precedence level, ordered from lowest to highest.

FAQ

{{< faq question="Which parser library should I use?" >}} Megaparsec for good error messages and general use. Attoparsec for high-performance streaming. Parsec for compatibility (older code). {{< /faq >}}

{{< faq question="What is the difference between lexing and parsing?" >}} Lexing tokenizes input into tokens. Parsing builds an AST from tokens. Most combinator libraries skip separate lexing. {{< /faq >}}

{{< faq question="How do I make parsers fast?" >}} Avoid Backtracking (try). Use commit points. For large input, use Attoparsec which works on Text/ByteString. {{< /faq >}}

What's Next

Now learn about concurrency in Haskell.

Topic Description Link
Concurrency Concurrent Haskell {{< ref "21-concurrency" >}}
Profiling Performance profiling {{< ref "23-profiling" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro