这里到底发生了什么:

"Couldn't match kind `*' against `#'"

我正在使用TemplateHaskell(ghci -XTemplateHaskell)在GHCi中尝试以下操作
$(reify ''Show >>= dataToExpQ (const Nothing))

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

我的目标是:
info :: Info
info = $(reify ''Show >>= dataToExpQ (const Nothing))

我真的不明白该错误消息,无论如何,“#”是什么?如果有#,也有# -> #* -> #吗?它是否与种类相关,就像种类与类型相关(尽管我不知道那可能是什么)?

好的,所以我现在知道GHC具有种类的层次结构,而#是一种特殊的未装箱类型。很好,但是为什么会弹出此错误?也许未装箱的类型不能很好地发挥作用?

我还不确定这对我来说是否有意义,因为我认为unboxed类型是由编译器执行的优化。我还认为,如果存在Data实例,则该实例必须存在于可能包含在数据结构中的所有类型。

经过进一步调查,我相信Names会带来问题,是否有办法在dataToExpQ中规避它们?无论如何如何使用该参数?

最佳答案

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

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

因此,问题在于NameFlavour的Data实例违反了dataToExpQ假定的不变式。但是不用担心!这种情况恰好是dataToExpQ接受参数的原因:该参数使我们可以为麻烦的类型提供特殊处理。下面,我这样做是为了正确地验证具有未装箱整数字段的NameFlavour构造函数。

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

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MagicHash #-}

module Stage0 where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

import GHC.Types (Int(I#))
import GHC.Prim (Int#)

unboxed :: Int# -> Q Exp
unboxed i = litE $ intPrimL $ toInteger $ I# i -- TH does support unboxed literals

nameFlavorToQExp :: NameFlavour -> Maybe (Q Exp)
nameFlavorToQExp n = case n of
  NameU i -> Just [| NameU $(unboxed i) |]
  NameL i -> Just [| NameL $(unboxed i) |]
  _ -> Nothing

然后以下内容为我编译。
{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH
import Language.Haskell.TH.Quote

import Generics.SYB
import Stage0

info :: Info
info = $(reify ''Show >>= dataToExpQ (mkQ Nothing nameFlavorToQExp))

CAVEAT编程器在这里,我们向后弯曲的未装箱的整数对应于GHC内部使用的“唯一数”。它们不一定要序列化。根据您使用的结果Info值的方式,这可能会导致爆炸。

另请注意,在调整Show的大小时,您还要调整范围内Show的每个实例。
  • 其中有很多-这会生成一个很大的语法术语。
  • 正如the documentation所说,这些实例不包括方法定义。

  • HTH。

    09-12 12:06