Template Haskell数据声明,用于派生Show功能。

8
以下代码无法编译:
import Language.Haskell.TH
makeAlpha n = [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]

我完全看不懂这个错误的含义:

Can't derive instances where the instance context mentions
type variables that are not data type parameters
  Offending constraint: Show t_d
When deriving the instance for (Show Alpha)
In the Template Haskell quotation
  [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]
In the expression:
  [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]

这样做推导是否可行?

我认为问题可能在于它在获取n之前尝试派生实例;也就是说,它试图扩展您的splice以包含这些实例,但无法这样做,因为它不知道$(conT n)看起来像什么。不过我不确定。 - ehird
我也有同样的想法,但我经常不确定Template Haskell允许什么和不允许什么...在这种情况下,我认为很明显它不能推导出实例,需要等待函数使用扩展。这是个错误吗? - user1002430
嗯,等等,应该是 data Alpha = $(conT n) 或者类似的东西吧?我认为你现在的代码存在类型错误,至少从 Dec 的定义上看是这样的。 - ehird
我希望Alpha可以取决于我后来确定的类型。如果您删除派生,它将正常工作,并且编译器将生成正确的代码。 - user1002430
1个回答

7
这个问题的原因是 TH 引号在编译时会进行类型检查,其中的 splices 会被替换为变量。通常情况下,这是一个好主意,因为它可以在运行 splice 之前检测到许多种类的问题,但在某些情况下,这可能会导致编译器错误地拒绝生成有效代码的 splice。在这种情况下,这意味着编译器尝试检查此代码:
data Alpha = Alpha t deriving (Show, Read)

这不起作用,因为派生的 ShowRead 实例需要使用 tShowRead,但由于 t 不是 Alpha 的类型参数,所以它无法添加必要的约束。当然,在运行这个代码段时,t 会被具体类型替换,因此适当的实例将可用而无需任何约束,所以这是编译器过于谨慎的情况之一。
解决方法是不使用引号,而是使用 TH 组合器,它们不受这些额外检查的限制。虽然有点混乱,但它能够工作。
makeAlpha n = sequence [dataD (cxt []) alpha []
                [normalC alpha [strictType notStrict (conT n)]] [''Show, ''Read]]
  where alpha = mkName "Alpha"

目前有放宽对报价的检查的讨论, 但现在你只能处理它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接