我有一个TemplateHaskell函数创建一个类名:
test :: Q [Dec]
test = do
clsname <- newName "A"
a <- newName "a"
return [
ClassD [] clsname [PlainTV a] [][]
]
使用newName
生成类名,因此应该没有冲突(原因是我直接在TH中创建实例,并且不需要它可见)。
test
test
Schema.hs:27:1: error:
Multiple declarations of ‘A’
Declared at: Schema.hs:26:1
Schema.hs:27:1
然而,使用Debug.Trace测试它,A
的名称确实类似于A_1627476119
。这在GHC 7.10.3和GHC8中都是相同的。这是一个错误还是我理解错了?
答案 0 :(得分:0)
newName
并没有像你想象的那样工作。 不会创建一个随机未使用的符号,使用提供的字符串仅作为前缀,并且 - 据我所知 - 模板Haskell没有标准函数去做。但是,您可以通过以下方式获得相同的效果:
gensym :: String -> Q Name
gensym pfx = mkName . show <$> newName pfx
应该适用于您的匿名类:
test :: Q [Dec]
test = do
clsname <- gensym "A" -- use gensym here
a <- newName "a" -- this is fine, though
return [
ClassD [] clsname [PlainTV a] [][]
]
如果您对更长的解释感兴趣,那么newName
做做的是创建一个无法被&#34;更深层次&#34;绑定,但它通过将附加信息附加到创建的Name
对象,而不是通过修改实际名称来实现。如果使用这样的Name
来创建绑定,则绑定将使用原始的提供的名称,而不是损坏的版本。
要查看此内容,请先注意Name
创建的mkName
结构比其可打印的表示形式更多:
GHCi> :m Language.Haskell.TH Language.Haskell.TH.Syntax
GHCi> nm <- runQ (newName "foo")
GHCi> nm
foo_16
GHCi> let Name occname nmtype = nm
GHCi> occname
OccName "foo"
GHCi> nmtype
NameU 16
GHCi>
其次,请注意引用:
[d| one = 1 |]
相当于使用newName
的以下do-block:
do nm <- newName "one"
decl <- valD (varP nm) (normalB (litE (integerL 1))) []
return [decl]
所以你可以写下以下内容:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
$(do nm <- newName "one"
decl <- valD (varP nm) (normalB (litE (integerL 1))) []
return [decl])
main = print one
说明&#34; one&#34;由newName
创建的名称可用于创建顶级绑定,该绑定在main
函数中使用其简单,未经修饰的名称one
引用。 (如果你在这里创建了一个额外的拼接副本,你就会得到相同的#34;多个声明&#34;你的课程错误。)