cassette-0.2.0: A combinator library for simultaneously defining parsers and pretty printers.
Safe HaskellNone
LanguageHaskell2010

Text.Cassette

Description

The combinators of this library are all pairs of functions going in opposite directions. These pairs are called cassettes, sporting two tracks (the two functions), one of which is read in one direction, the other of which (accessed by flipping the cassette) is read in the opposite direction.

Example

Expand

Consider the data type for abstract syntax trees of the λ-calculus:

>>> :{
  type Ident = String
  data Term where
    Var :: Ident -> Term
    Abs :: Ident -> Term -> Term
    App :: Term -> Term -> Term
  deriving instance Show Term
  makePrisms ''Term
:}

Given a few constructor-wrapping prisms (generated by makePrisms from the lens library or otherwise) and lifting them to cassette leads (the definitions are mechanical), ...

>>> :{
  varL = prismL _Var
  absL = prismL _Abs . pairL
  appL = prismL _App . pairL
:}

... the concrete syntax for terms of the λ-calculus can be defined as follows:

>>> :{
  term :: PP Term
  term =
    varL --> ident <>
    absL --> char '^' . ident . char '.' . optSpace . term <>
    appL --> parens (term . sepSpace . term)
  parens p = char '(' . p . char ')'
  ident = consL --> letter . many alphaNum
:}

From this single specification, we can extract a parser, using parse, and also a pretty printer, using pretty.

>>> parse term "^x. (x x)"
Just (Abs "x" (App (Var "x") (Var "x")))
>>> pretty term (Abs "x" (App (Var "x") (Var "x")))
Just "^x. (x x)"

Grammar specifications

Specifications are built from primitive and derived combinators, which affect the input string in some way. For each constructor of each datatype, we need to write a lead, which is a pair of a construction function and a destruction function. Leads are pure combinators that do not affect the input string. By convention, we suffix their name with L. A number of leads for standard data types are defined in the Text.Cassette.Lead module.

Documentation