Antiquotation/splices for quasiquoters
Summary
(This is a low-effort alternative to a GHC proposal, although it definitely needs one)
At the moment quasiquoters can only process their entire input as a string. In particular, they have no access to antiquotation/splicing, even though that would be useful. Several quasiquoters implement their own antiquotation using Haskell parsers, which is as fragile and awkward as you would expect (PyF, various of the quasiquoters in Yesod, maybe more).
e.g. a HTML quasiquoter that allows splicing in Haskell values of type HTML
; a proper string interpolation quasiquoter.
We could give quasiquoters an interface that allows this, namely:
data Part = StringPart String | ExpPart Exp
data QuasiQuoter = QuasiQuoter {
...
-- New field to avoid backwards-compatibility issues
, quoteExp' :: Maybe ([Part] -> Q Exp)
}
Then a quasiquoter invocation such as [foo| first bit $(2+4) second bit|]
would
- Evaluate each of the splices, and convert it to an
Exp
- Pass the list of strings and evaluated
Exp
s tofoo.quoteExp'
This would make quasiquoters much more powerful and enable behaviour that there is evident demand for, given the horrible workarounds that people are using today. It would also make quasiquotes look and behave much more like Haskell syntax quotes, which seems good from a consistency perspective.
Backwards compatibility:
- Add the new parsers as new optional fields in
QuasiQuoter
- We need escaping syntax to produce a
$
as part of normal text; adding this unilaterally would break existing uses of quasiquoters. We could parse$
as the start of the splice only if the new quoter field is notNothing
, so the quasiquoter has to explicitly opt in to this.