Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a template haskell function for quoting?

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
like image 491
scravy Avatar asked Mar 27 '13 15:03

scravy


2 Answers

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.

like image 106
nushio Avatar answered Dec 25 '22 22:12

nushio


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.

like image 33
Jonathan Fischoff Avatar answered Dec 25 '22 21:12

Jonathan Fischoff