haskelltemplate-haskell

Print and execute a string


I find myself writing a lot of code like

putStr "foo (bar 1) (bar 2) ="
print $ foo (bar 1) (bar 2)

The trouble is, the printed message can get out of sync with the actual executed code. The obvious solution is to auto-generate this code.

One way to do that would be to put all the text in a file, and write a small program that reads the file and generates Haskell source code from it. But another alternative is to use Template Haskell.

Does anybody know how I would go about writing a function that takes a String and generates the above code from it? I'm guessing it should be pretty easy, but TH is not well documented.


Solution

  • You can parse Haskell code using the haskell-src-meta package. Here's a quick example how you could combine this with Template Haskell.

    {-# LANGUAGE TemplateHaskell #-}
    
    import Language.Haskell.TH
    import Language.Haskell.TH.Quote
    import Language.Haskell.Meta
    
    runShow = QuasiQuoter
        { quoteExp  = runShowQQ
        , quotePat  = undefined
        , quoteType = undefined
        , quoteDec  = undefined
        }
    
    runShowQQ :: String -> Q Exp
    runShowQQ s = do
        let s'          = s ++ " = "
            Right exp = parseExp s
            printExp  = appE [|print|] (return exp)
        infixApp [|putStr s'|] [|(>>)|] printExp
    

    And you would use it like this

    {-# LANGUAGE QuasiQuotes #-}
    
    [runShow|foo (bar 1) (bar 2)|]