A couple of weeks ago I stumbled across a Template Haskell question on the
Haskell sub-reddit. This was quite exciting
because I rarely see TH questions, and this one was by someone working
on something which was quite similar to what I had done: they were writing
a code generator, and had pure functions of type
Exp -> Exp -> Exp, but
wanted to leverage TH's quasi-quotation syntax (e.g.
[| \p -> p + 1 |])
as a syntactic short-hand. Alas these quasi-quotes are of type
Q Exp, so
the question becomes, how to escape
I had to do exactly this, so I knew an answer: use
commenter pointed at this Overloaded Quotation Brackets GHC
Proposal which I was
not aware of and is a much more elegant solution, available since GHC 9.0.1.
There was something odd about the question, though.
Sometime later on, I checked back to find that the thread had been deleted. It turns out it was one of a set of duplicate posts with exactly the same question. Spammers are copying old questions and reposting them, presumably in an attempt to harvest "Reddit karma".
When I learned that, my sense of oddness about the question remained, so I went to find the original thread, to discover I wrote the original question a year ago and had therefore literally answered my own question a year later.
Back to the more elegant solution. In GHC versions 9 onwards, quasi-quotation returns a different type that is not bound up in the Q Monad:
λ> :t [| 42 |] [| 42 |] :: Language.Haskell.TH.Lib.Internal.ExpQ λ> [| 42 |] <interactive>:5:1: error: • No instance for (Show Language.Haskell.TH.Lib.Internal.ExpQ) arising from a use of ‘print’ • In a stmt of an interactive GHCi command: print it
λ> :t [| 42 |] [| 42 |] :: Language.Haskell.TH.Syntax.Quote m => m Language.Haskell.TH.Syntax.Exp λ> [| 42 |] LitE (IntegerL 42)