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
不要做的就是創建一個名稱不能被「更深」的綁定捕獲,但它通過附加信息附加到創建的對象上,而不是通過修改實際名稱來實現。如果使用這樣的Name
來創建綁定,綁定使用提供的原始名稱,而不是損壞的版本。
看到這一點,首先注意到,mkName
創建Name
有更多的結構比它可顯示的表示顯示:
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 |]
相當於下面的do-block使用newName
:
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
示出了由newName
創建的「一」名稱可以被用來創建一個頂級綁定在main
功能使用其平原,縵,名稱引用:one
。 (如果您在此處創建了拼接的額外副本,則會得到與您的類相同的「多個聲明」錯誤。)