模板 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 中没有歧义地共享名称)。