如何明确调用haskell语法的quasiquoter?

时间:2016-12-05 18:16:51

标签: haskell template-haskell

我正在HaTeX之上构建一个eDSL。我面临的问题是我想在我的LaTeX文档中显示Haskell表达式,并且我想使用相同的Haskell表达式来帮助生成文档。

显而易见的答案是复制并粘贴表达式,使其既可以显示也可以显示。我想避免这种情况,因为表达式可能会发生变化。

我想象的是一个准引号,它既可以拼接其内容,也可以输出代表它的字符串。

例如,以下是我要输入的内容:

document = do
    title "this is an example document"
    paragraph "This is normal text. We will now show the Haskell code that generates a table"
    [quoted| makeTable ["heading1","heading2"] ["cell1","cell2"] |]

我希望准引言扩展为:

document = do
    title "this is an example document"
    paragraph "This is normal text. We will now show the Haskell code that generates a table"
    makeTable ["heading1","heading2"] ["cell1","cell2"]
    listing Haskell "makeTable [\"heading1\",\"heading2\"] [\"cell1\",\"cell2\"]"

为此,我需要写一个QuasiQuoter:

quoted :: QuasiQuoter
quoted = QuasiQuoter
     { quoteExp = \str -> [e| $(_ str) >> listing Haskell $(lift str) |] }

我不确定在$(_ str)中用什么替换洞。我需要用Haskell表达式准引号替换它,但我不确定如何调用它。如果ee :: QuasiQuoter,我可以用$(quoteExp e str)填补漏洞,但遗憾的是它不起作用。我应该填什么?

1 个答案:

答案 0 :(得分:5)

简短的回答:没有简单的方法。由于某种原因,This question 仍然 未得到答复。 Haskell的String -> Q Exp很难。最好的方法可能是haskell-src-meta,它提供了返回Template Haskell AST的解析器。特别是Language.Haskell.Meta.Parse模块为我们提供了parseExp :: String -> Either String Exp

import Language.Haskell.Meta.Parse (parseExp)

quoted :: QuasiQuoter
quoted = QuasiQuoter
     { quoteExp = \str ->
         case parseExp str of
           Left msg -> fail "Could not parse expression."
           Right exp -> [e| $(pure exp) >> listing Haskell $(liftString str) |] }