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
, а не путем изменения фактического имени. Если для создания привязки используется такой 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 |]
эквивалентно нижеследующий 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
. (Если вы создали дополнительную копию сращивания здесь, вы получите те же «множественные декларации», которые вы получили с вашими классами.)