模板 Haskell 和 Quasiquotes 的语法
模板 Haskell 由 -XTemplateHaskell GHC 扩展启用。此扩展启用了本节中进一步详述的所有语法功能。有关 Template Haskell 的完整详细信息,请参见用户指南 。
接头
-
splice 是一个由 Template Haskell 启用的新语法实体,写为
$(...),其中(...)是一个表达式。 -
$和表达式的第一个字符之间不能有空格; 和模板 Haskell 覆盖了$运算符的解析 - 例如,f$g通常被解析为($) f g,而启用了 Template Haskell,它被解析为拼接。 -
当拼接出现在顶层时,可以省略
$。在这种情况下,拼接表达式是整行。 -
splice 表示在编译时运行以生成 Haskell AST 的代码,并且该 AST 被编译为 Haskell 代码并插入到程序中
-
拼接可以代替:表达式,模式,类型和顶级声明。在每种情况下,拼接表达的类型分别是
Q Exp,Q Pat,Q Type,Q [Decl]。请注意,声明拼接可能只出现在顶层,而其他拼接可能分别出现在其他表达式,模式或类型中。
表达式引用(注意: 不是 QuasiQuotation)
-
表达式引用是一个新的语法实体,写成以下之一:
[e|..|]或[|..|]-..是一个表达式,引用的类型为Q Exp;[p|..|]-..是一种模式,引用的类型为Q Pat;[t|..|]-..是一个类型,引用的类型为Q Type;[d|..|]-..是一个声明列表,引用的类型为Q [Dec]。
-
表达式引用采用编译时程序并生成该程序表示的 AST。
-
在没有拼接的情况下在引用中使用值(例如
\x -> [| x |])对应于\x -> [| $(lift x) |]的语法糖,其中lift::Lift t => t -> Q Exp来自类
class Lift t where
lift::t -> Q Exp
default lift::Data t => t -> Q Exp
键入的拼接和引用
-
类型拼接与之前提到的(无类型)拼接类似,并且写为
$$(..),其中(..)是表达式。 -
如果
e的类型为Q (TExp a),则$$e的类型为a。 -
输入的引文采用
[||..||]的形式,其中..是a类型的表达式; 结果引号的类型为Q (TExp a)。 -
键入的表达式可以转换为无类型的表达式:
unType::TExp a -> Exp。
QuasiQuotes
-
QuasiQuotes 概括了表达式引用 - 之前,表达式引用使用的解析器是固定集(
e,p,t,d)之一,但 QuasiQuotes 允许定义自定义解析器并在编译时使用它来生成代码。准引用可以出现在与常规引用相同的上下文中。 -
准引用被写为
[iden|...|],其中iden是Language.Haskell.TH.Quote.QuasiQuoter类型的标识符。 -
QuasiQuoter简单地由四个解析器组成,每个解析器可以出现一个不同的上下文:
data QuasiQuoter = QuasiQuoter { quoteExp :: String -> Q Exp,
quotePat :: String -> Q Pat,
quoteType::String -> Q Type,
quoteDec :: String -> Q [Dec] }
名称
-
Haskell 标识符由
Language.Haskell.TH.Syntax.Name类型表示。名称形成抽象语法树的叶子,表示模板 Haskell 中的 Haskell 程序。 -
当前在范围内的标识符可以变为具有以下任一名称的名称:
'e或'T。在第一种情况下,e在表达式范围内被解释,而在第二种情况下,T在类型范围内(回想一下类型和值构造函数可以在 Haskell 中没有歧义地共享名称)。