TemplateHaskell类名与冲突newName

时间:2016-12-13 21:12:19

标签: haskell template-haskell

我有一个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中都是相同的。这是一个错误还是我理解错了?

1 个答案:

答案 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;你的课程错误。)