I am playing with Template Haskell. I want to create a quasi quoter which allows me to create default initializers for records, i.e. something like
[record| data Config = { shouldDoX = True; featureY :: Integer, optionZ = Nothing } |]
should create a function
defaultConfig = Config { shouldDoX = True, optionZ = Nothing }
Basically it's the same syntax as data declarations, extended by default values. Now record
is a custom QuasiQuoter, however there are expressions and types inside which I do not want to parse myself. Ideally I would only have to divide the block inside the curly braces into statements and look for =
and ::
.
So I'm looking for a function which effectively does the same as quoting with [e| ...|]
or [t| ...|]
. I've searched Hoogle for a function String -> ExpQ
or String -> Q Exp
but didn't find anything.
In case I was not clear about what I'm looking for: I know about QuasiQuoters. As I mentioned: record
is a QuasiQuoter. Now the string that is passed to my quasi quoter contains Expressions (like Node 7 (Node 8 Nil Nil) Nil
) and Types (like True
or Maybe (Either A B)
). I could parse these myself, but I hope that there is a function which will do it for me, just as if I passed the string into a quotation like [e|...|]
.
So: I'm looking for a function which I can feed an expression as a String, or a Type as a String, and which returns the adequate Exp
or Type
object. I believe it must live in the Q monad, since it should evaluate the expression or type based on the context (just like quotations do).
functionOfMyDreams "Node 7 (Node 8 Nil Nil) Nil" :: Q Exp
I think the functions
parseExp :: String -> Either String Exp
parseType :: String -> Either String Type
from haskell-src-meta
package are what you want.
http://hackage.haskell.org/package/haskell-src-meta-0.6.0.4/docs/Language-Haskell-Meta-Parse-Careful.html
Here is a self-contained example of an quasiquoter that can antiquote and embed Haskell expressions using haskell-src-meta
.
You have the right idea, but it would be a function like String -> Q [Dec]
To make a quasiquoter you have to create a value of type QuasiQuoter which has a four functions of type String -> Q Blah
where Blah is the Template Haskell type you are splicing in.
In your case you only need to define the declaration quoter.
quoteRecord :: String -> Q [Dec]
quoteRecord = ...
record :: QuasiQuoter
record = QuasiQuoter (error "record is not a expression quoter")
(error "record is not a pattern quoter")
(error "record is not a type quoter")
quoteRecord
You can then use your record quasiquoter in another file
[record| ... |]
There is a good walk through on the Haskell wiki
You also might want to check out BNFC-meta which will generate a quasiquoter from a grammar.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With