[http://www.eecs.harvard.edu/~mainland/ghc-quasiquoting/mainland07quasiquoting.pdf Why It's Nice to be Quoted: Quasiquoting for Haskell].

+

[http://www.eecs.harvard.edu/~mainland/publications/mainland07quasiquoting.pdf Why It's Nice to be Quoted: Quasiquoting for Haskell].

Quasiquoting allows programmers to use custom, domain-specific syntax to construct fragments of their program. Along with Haskell's existing support for domain specific languages, you are now free to use new syntactic forms for your EDSLs.

Quasiquoting allows programmers to use custom, domain-specific syntax to construct fragments of their program. Along with Haskell's existing support for domain specific languages, you are now free to use new syntactic forms for your EDSLs.

* [http://hackage.haskell.org/package/haskell-src-meta haskell-src-meta contains quite a few QuasiQuoters], though the toy examples are no longer exported and others have been moved to [http://hackage.haskell.org/package/applicative-quoters applicative-quoters]

+

* [http://hackage.haskell.org/package/command-qq command-qq]

+

* [http://hackage.haskell.org/package/process-qq process-qq]

+

* [http://hackage.haskell.org/package/Rlang-QQ Rlang-QQ is a quasiquoter for inline R]

* [http://quasimal.com/posts/2012-05-25-quasitext-and-quasiquoting.html A look at QuasiQuotation]

−

Note that the syntax for

+

Note that the syntax for quasiquotation has changed since the paper was written: in GHC 7 one writes <hask>[expr|...|]</hask> instead of <hask>[:expr|...|]</hask>. GHC 6.12 uses <hask>[$expr|...|]</hask>. Quasiquotation appeared in GHC 6.9 and is enabled with the <code>QuasiQuotes</code> language option (<code>-XQuasiQuotes</code> on the command line or <hask>{-# LANGUAGE QuasiQuotes #-}</hask> in a source file).

−

quasiquotation has changed since the paper was written: now one writes

Revision as of 13:42, 2 October 2013

Contents

1 introduction

Quasiquoting allows programmers to use custom, domain-specific syntax to construct fragments of their program. Along with Haskell's existing support for domain specific languages, you are now free to use new syntactic forms for your EDSLs.

Note that the syntax for quasiquotation has changed since the paper was written: in GHC 7 one writes

[expr|...|]

instead of

[:expr|...|]

. GHC 6.12 uses

[$expr|...|]

. Quasiquotation appeared in GHC 6.9 and is enabled with the QuasiQuotes language option (-XQuasiQuotes on the command line or

{-# LANGUAGE QuasiQuotes #-}

in a source file).

We show how to build a quasiquoter for a simple mathematical expression
language. Although the example is small, it demonstrates all aspects of building
a quasiquoter. We do not mean to suggest that one gains much from a quasiquoter
for such a small language relative to using abstract syntax directly except from
a pedagogical point of view---this is just a tutorial!

The tutorial is runnable if its contents is placed in files as follows:

Place the contents of the #Syntax and #Parsing sections in the file Expr.hs
with header

2 Syntax

Our simple expression language consists of integers, the standard operators
+,x,*,/, and parenthesized expressions. We will write a single parser that takes
concrete syntax for this language and transforms it to abstract syntax. Using
the SYB approach to generic programming, we will then use this parser to produce
expression and pattern quasiquoters. Our quasiquoter will allow us to write

[expr|1+3|]

directly in Haskell source code instead of the

corresponding abstract syntax.

An obvious datatype for the abstract syntax of this simple language is:

Unfortunately, this won't do for our quasiquoter. First of all, the SYB
technique we use cannot handle function types in a generic way, so the BinopExpr
constructor must be modified. SYB also requires that we derive Typeable and
Data, a trivial change. Finally, we want to support antiquoting for two
syntactic categories, expressions and integers. With antiquoting support, we can
write [expr|$x + $int:y|] where x and y are in-scope variables with types Expr
and Integer, respectively. The final data types for our abstract syntax are:

3 Parsing

We use Parsec to write a parser for our expression language. Note that we have
(somewhat arbitrarily) chosen the syntax for antiquotaton to be as in the above
example; a quasiquoter may choose whatever syntax she wishes.

The helper function parseExpr takes a source code position (consisting of a file
name, line and column) and a string and returns a value of type Expr. This
helper function also ensures that we can parse the whole string rather than just
a prefix.

4 The Quasiquoter

Remember, our quasiquoter allows us to write expression in our simple language,
such as [expr|2 * 3|], directly in Haskell source code. This requires that the
variable expr be in-scope when the quasiquote is encountered, and that it is
bound to a value of type Language.Haskell.TH.Quote.QuasiQuoter, which contains
an expression quoter and a pattern quoter. Note that expr must obey the same
stage restrictions as Template Haskell; in particular, it may not be defined in
the same module where it is used as a quasiquoter, but must be imported.

Our expression and pattern quoters are quoteExprExp and quoteExprPat,
respectively, so our quasiquoter expr is written as follows:

Our quasiquoters re-use the parser we wrote in the previous section, parseExpr,
and make use of the generic functions dataToExpQ and dataToPatQ (described in
the Haskell Workshop paper). These functions, from the Language.Haskell.TH.Quote
package, take a Haskell value and reflect it back into the language as Template
Haskell abstract syntax. The catch is that we don't want to handle all values
generically: antiquoted values must be handled specially. Consider the AntiExpr
constructor; we don't want this constructor to be mapped to Template Haskell
abstract syntax for the AntiExpr constructor, but to abstract syntax for the
Haskell variable named by the constructor's argument. The extQ combinator allows
us to do this nicely by defining a function antiExprExp that handles
antiquotations.