QuasiQuote with arguments

I want to write a quote in Haskell. The name argument must be passed to the gen function to generate the declaration.

quote :: String -> QuasiQuoter quote name = QuasiQuoter { quoteExp = undefined, quotePat = undefined, quoteType = undefined, quoteDec = \jsonStr -> gen name (getValue str) } 

However, it seems like I cannot use a quote like this

 [quote "Hello"| from x to y |] 

Since Haskell does not allow quote declarations and quotes to be in the same file, which is annoying, what can I do to pass an argument from the outside to the quote?

+8
haskell template-haskell
source share
1 answer

You have two options:

  • Switch to using the $(...) splice,
  • Encode your parameter in a quasi-cycle in the input line.

With the splice syntax, your example would look like this:

 quote :: String -> String -> Q [Dec] quote name jsonStr = gen name (getValue jsonStr) 

and calling it looks like this: $(quote "Hello" "from x to y")

To demonstrate option 2, here is a simple snippet that surrounds a literal string with a symbol:

 import Language.Haskell.TH (litE, stringL) import Language.Haskell.TH.Quote surround :: QuasiQuoter surround = QuasiQuoter { quoteExp = litE . stringL . (\(c:s) -> [c] ++ s ++ [c]) , quotePat = undefined , quoteType = undefined , quoteDec = undefined } -- in another file: main = print [surround|_some text|] -- prints "_some text_" 

The first character of the input string is interpreted as the bracket character to use. In fact, we passed the Char parameter to a function of type Char -> QuasiQuoter .

For more complex parameters or several parameters, you will have to create your own syntax and parser to decode them.

Update: Here is a slightly more complex example where calling [foo| var xyz|] [foo| var xyz|] treats var as a variable name and xyz as a literal string:

 -- [foo| var xyz|] is translated to: var ++ "xyz" foo :: QuasiQuoter foo = QuasiQuoter { quoteExp = go , quotePat = undefined , quoteType = undefined , quoteDec = undefined } where go str = infixE (Just $ varE (mkName var)) (varE $ mkName "++") (Just $ litE (stringL arg1)) where (var:arg1:_) = words str 
+6
source share

All Articles