4

Quasi-quotes 允许在编译期间生成 AST 代码,但它会在 Quasi-quote 的编写位置插入生成的代码。是否可以以任何方式将编译时生成的代码插入其他地方?例如,在特定的模块文件中,与编写 QQ 的模块文件不同?这将取决于硬编码的模块结构,但这很好。

如果 QQ 无法做到这一点,但任何人都知道实现它的不同方式,我愿意提供建议。

4

1 回答 1

4

要回答这个问题,了解什么是准报价者会很有帮助。从GHC 文档中,准引用者的值是

data QuasiQuoter = QuasiQuoter { quoteExp  :: String -> Q Exp,
                                 quotePat  :: String -> Q Pat,
                                 quoteType :: String -> Q Type,
                                 quoteDec  :: String -> Q [Dec] }

也就是说,它是从任意字符串到一个或多个ExpQPatQTypeQ和的解析器DecQ,它们分别是表达式、模式、类型和声明的模板 Haskell 表示。

当您使用准引号时,GHC 将解析器应用到 String 以创建一个ExpQ(或其他类型),然后拼接生成的模板 haskell 表达式以产生一个实际值。

听起来您要求做的是将准引号解析和拼接分开,以便您可以访问 TH 表达式。然后你可以将该表达式导入另一个模块并自己在那里拼接。

知道准报价者的类型,很明显这是可能的。通常你使用QQ作为

-- file Expr.hs
eval :: Expr -> Integer
expr = QuasiQuoter { quoteExp = parseExprExp, quotePat =  parseExprPat }

-- file Foo.hs
import Expr
myInt = eval [expr|1 + 2|]

相反,您可以自己提取解析器,获取 TH 表达式,然后再拼接:

-- file Foo.hs
import Expr

-- run the QQ parser
myInt_TH :: ExpQ
myInt_TH = quoteExp expr "1 + 2"

-- file Bar.hs
import Foo.hs

-- run the TH splice
myInt = $(myInt_TH)

当然,如果您自己编写所有这些,您可以跳过准引号并直接使用解析器和模板 Haskell。无论哪种方式,这几乎都是一样的。

于 2012-04-05T09:51:39.067 回答