DeriveAnyClass 与空实例
DeriveAnyClass vs Empty Instance
假设我有这个类型族,如果传递给它的类型不是记录,它会在编译时抛出自定义类型错误:
type family IsRecord (a :: Type) where
...
现在我有了这种类型 class,它具有默认实现的方法,但通过添加 IsRecord
约束要求该类型是记录:
class IsRecord a => Foo a where
foo :: Text
foo = "foo"
当尝试错误使用它时,如果我们将其用作类型不是记录的常规实例,它会成功编译失败:
data Bar = Bar
instance Foo Bar -- error: Bar is not a record
但是如果我启用 -XDeriveAnyClass
并将其添加到派生子句中,这不会编译失败,完全忽略约束:
data Bar = Bar
deriving (Foo)
我知道 DeriveAnyClass
生成一个空的实例声明,这是我在第一个示例中所做的,但它仍然没有抛出错误。怎么回事?
我正在使用 GHC 8.6.4
哇!我打算将其标记为 的副本,但自从提出并回答了该问题后,GHC 的行为似乎发生了变化!
无论如何,如果你问——无论是在 ghci 中使用 :i
还是在启动 ghci 之前使用 -ddump-deriv
—— 编译器做了什么,很明显你的情况有什么区别:
> :i Bar
data Bar = Bar -- Defined at test.hs:15:1
instance IsRecord Bar => Foo Bar -- Defined at test.hs:16:13
确实,如果您更改非DeriveAnyClass
版本的代码以匹配,写
instance IsRecord Bar => Foo Bar
而不是
instance Foo Bar
一切正常。如何选择这个实例上下文的细节似乎有点复杂;你可以阅读 GHC 手册对它的描述 here,尽管我怀疑那里的描述不是很准确就是不完整,因为如果我严格遵守,我不会得到编译器在这里所做的相同答案文件中规定的规则。 (我怀疑 true 的答案是它首先写入实例,然后只进行通常的类型推断,并将以这种方式发现的任何约束复制到实例上下文中。)
假设我有这个类型族,如果传递给它的类型不是记录,它会在编译时抛出自定义类型错误:
type family IsRecord (a :: Type) where
...
现在我有了这种类型 class,它具有默认实现的方法,但通过添加 IsRecord
约束要求该类型是记录:
class IsRecord a => Foo a where
foo :: Text
foo = "foo"
当尝试错误使用它时,如果我们将其用作类型不是记录的常规实例,它会成功编译失败:
data Bar = Bar
instance Foo Bar -- error: Bar is not a record
但是如果我启用 -XDeriveAnyClass
并将其添加到派生子句中,这不会编译失败,完全忽略约束:
data Bar = Bar
deriving (Foo)
我知道 DeriveAnyClass
生成一个空的实例声明,这是我在第一个示例中所做的,但它仍然没有抛出错误。怎么回事?
我正在使用 GHC 8.6.4
哇!我打算将其标记为
无论如何,如果你问——无论是在 ghci 中使用 :i
还是在启动 ghci 之前使用 -ddump-deriv
—— 编译器做了什么,很明显你的情况有什么区别:
> :i Bar
data Bar = Bar -- Defined at test.hs:15:1
instance IsRecord Bar => Foo Bar -- Defined at test.hs:16:13
确实,如果您更改非DeriveAnyClass
版本的代码以匹配,写
instance IsRecord Bar => Foo Bar
而不是
instance Foo Bar
一切正常。如何选择这个实例上下文的细节似乎有点复杂;你可以阅读 GHC 手册对它的描述 here,尽管我怀疑那里的描述不是很准确就是不完整,因为如果我严格遵守,我不会得到编译器在这里所做的相同答案文件中规定的规则。 (我怀疑 true 的答案是它首先写入实例,然后只进行通常的类型推断,并将以这种方式发现的任何约束复制到实例上下文中。)