jmtd → log → Answering my own Template Haskell question
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 Q
?
I had to do exactly this, so I knew an answer: use unsafePerformIO
. Another
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:
GHC 8.8.4:
λ> :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
GHC 9.0.1:
λ> :t [| 42 |]
[| 42 |]
:: Language.Haskell.TH.Syntax.Quote m =>
m Language.Haskell.TH.Syntax.Exp
λ> [| 42 |]
LitE (IntegerL 42)
Comments