【发布时间】:2014-07-23 00:38:44
【问题描述】:
我试图了解 Quasi Quoter 如何生成 TH 结构。所以我试图将Template Meta-programming for Haskell 中的第一个示例从引用格式转换为类型。
gen :: [Format] -> ExpQ -> ExpQ
gen [] x = x
gen (D:xs) x = [| \n -> $(gen xs [| $x ++ show n |]) |]
gen (S:xs) x = [| \s -> $(gen xs [| $x ++ s |]) |]
gen (L s:xs) x = gen xs [| $x ++ $(THS.lift s) |]
gen (D:xs) x 将转换为
gen (D:xs) x = lamE [varP $ mkName "n"]
(appE (appE (varE 'gen) (varE 'xs))
(uInfixE (x) (varE '(Prelude.++))
(appE (varE 'Prelude.show) (varE $ mkName "n"))))
但是,此片段不会编译对 'xs 的引用。
GHC 吐出以下错误:
src/Print/Default.hs:28:51:
Stage error: the non-top-level quoted name 'xs
must be used at the same stage at which is is bound
In the Template Haskell quotation 'xs
In the first argument of `varE', namely 'xs
In the second argument of `appE', namely `(varE 'xs)'
是否有其他方式需要引用函数参数的名称,以便 Template Haskell 能够使用它?
【问题讨论】:
-
转换不正确。请注意,在第一个版本中,引用的本地绑定名称也被拼接回。因此,如果
x是本地绑定的,则不能有$x,但可以有[| ... $x ... |]。在第二个版本中,您还没有这样做,这样做没有意义,因为lamE [varP ..]需要ExpQ但拼接内部的\n ->需要String。