这里到底发生了什么:
"Couldn't match kind `*' against `#'"
我使用TemplateHaskell(ghci -XTemplateHaskell
)
$(reify ''Show >>= dataToExpQ (const Nothing))
我希望得到一个Exp
(它有一个Show的实例)。我这样做是为了在应用程序中插入有关haskell类型的信息,使其可用作实际数据,而不是字符串。
我的目标如下:
info :: Info
info = $(reify ''Show >>= dataToExpQ (const Nothing))
我真的不明白这个错误信息,反正是什么'#'?如果有#
,还有# -> #
还是* -> #
?它是否与类型相关的类型有关(虽然我不知道那可能是什么)?
好的,所以我现在明白GHC有种类的层次结构,而'#'是一种特殊的无盒装类型。一切都很好,但为什么会弹出这个错误?也许未装箱的类型与genercis不相符?
我还不完全确定这对我有意义,因为我会认为未装箱的类型是由编译器执行的优化。我还认为,如果存在数据实例,则需要存在可能包含在数据结构中的所有类型。
经过进一步调查,我认为Names会造成问题,有没有办法在dataToExpQ中绕过它们?无论如何如何使用该论点?
答案 0 :(得分:4)
你是对的,导致问题的是名字。更具体地说,问题是NameFlavour数据类型在其某些字段中具有未装箱的整数。
Data NameFlavor实例上有一个Haddock注释会引发一些危险信号。如果你点击源代码,你会看到gfoldl定义基本上处理未整数的整数,如整数。 (实际上没有其他选择...)这最终会导致您看到的错误,因为dataToExpQ - 被欺骗性的Data NameFlavour实例欺骗 - 构建一个ExpName,在NameU实际期望的时候将NameU应用于(Int :: *) an(unboxed)(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 PROGRAMMER我们向后弯曲的未装箱整数对应于GHC内部使用的“唯一”。它们不一定是序列化的。根据您使用生成的Info值的方式,这可能会导致爆炸。
另请注意,在显示“显示”时,您还要为范围内的每个Show实例进行一次。
有很多 - 这会产生一个非常大的语法术语。
正如the documentation所述,这些实例不包含方法定义。
HTH。