无法与'#'匹配`*'

scr*_*avy 5 haskell generic-programming ghc template-haskell type-kinds

到底发生了什么:

"Couldn't match kind `*' against `#'"
Run Code Online (Sandbox Code Playgroud)

我在使用TemplateHaskell(ghci -XTemplateHaskell)的GHCi中尝试以下内容

$(reify ''Show >>= dataToExpQ (const Nothing))
Run Code Online (Sandbox Code Playgroud)

我希望得到一个Exp(这有一个Show的实例).我这样做是为了在应用程序中插入有关haskell类型的信息,使其可用作实际数据,而不是字符串.

我的目标是:

info :: Info
info = $(reify ''Show >>= dataToExpQ (const Nothing))
Run Code Online (Sandbox Code Playgroud)

我真的不明白这个错误信息,反正是什么'#'?如果有#,是否有也# -> #还是* -> #?它是否与类型相关的类型有关(虽然我不知道那可能是什么)?


好的,所以我现在明白GHC有各种各样的层次结构,而'#'是一种特殊的未装箱类型.一切都很好,但为什么会弹出这个错误?也许未装箱的类型与genercis不相称?

我还不完全确定这对我有意义,因为我认为未装箱的类型是由编译器执行的优化.我还认为,如果存在数据实例,则需要存在可能包含在数据结构中的所有类型.

经过进一步调查,我认为Names存在问题,有没有办法在dataToExpQ中规避它们?怎么用这个论点呢?

小智 4

你是对的,是名称导致了问题。更具体地说,问题在于NameFlavour数据类型的某些字段中有未装箱的整数。

\n\n

Data NameFlavor 实例上的 Haddock 注释引发了一些危险信号。如果您单击源代码,您将看到 gfoldl 定义本质上将未装箱的整数视为整数。(确实没有太多其他选择\xe2\x80\xa6)这最终会导致您看到的错误,因为 dataToExpQ \xe2\x80\x94\xc2\xa0 被欺骗性的 Data NameFlavour 实例 \xe2\ 欺骗x80\x94 构建一个 Exp 术语,当 NameU 实际上需要(未装箱的)(Int# :: #) 时,该术语将 NameU 应用于 (Int :: *)。

\n\n

所以问题是 NameFlavour 的 Data 实例不遵守 dataToExpQ 假设的不变量。但不用担心!这种情况完全属于 dataToExpQ 接受参数的原因:该参数让我们为麻烦的类型提供特殊处理。下面,我这样做是为了正确具体化具有未装箱整数字段的 NameFlavour 构造函数。

\n\n

可能有解决方案,但我不知道它们,所以我汇总了以下内容。由于 TH 分级限制,它需要一个单独的模块。

\n\n
{-# LANGUAGE TemplateHaskell #-}\n{-# LANGUAGE MagicHash #-}\n\nmodule Stage0 where\n\nimport Language.Haskell.TH\nimport Language.Haskell.TH.Syntax\n\nimport GHC.Types (Int(I#))\nimport GHC.Prim (Int#)\n\nunboxed :: Int# -> Q Exp\nunboxed i = litE $ intPrimL $ toInteger $ I# i -- TH does support unboxed literals\n\nnameFlavorToQExp :: NameFlavour -> Maybe (Q Exp)\nnameFlavorToQExp n = case n of\n  NameU i -> Just [| NameU $(unboxed i) |]\n  NameL i -> Just [| NameL $(unboxed i) |]\n  _ -> Nothing\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后为我编译以下内容。

\n\n
{-# LANGUAGE TemplateHaskell #-}\n\nimport Language.Haskell.TH\nimport Language.Haskell.TH.Quote\n\nimport Generics.SYB\nimport Stage0\n\ninfo :: Info\ninfo = $(reify \'\'Show >>= dataToExpQ (mkQ Nothing nameFlavorToQExp))\n
Run Code Online (Sandbox Code Playgroud)\n\n

程序员注意事项 我们在这里向后弯曲的未装箱整数对应于 GHC 内部使用的“唯一值”。它们不一定会被连载。根据您使用结果信息值的方式,这可能会导致爆炸。

\n\n

另请注意,在具体化 Show 时,您还具体化了范围内的 Show 的每个实例。

\n\n
    \n
  • 其中有很多 \xe2\x80\x94\xc2\xa0 这会生成一个相当大的语法术语。

  • \n
  • 正如文档所述,这些实例不包括方法定义。

  • \n
\n\n

HTH。

\n