Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell DeriveAnyClass与空实例_Haskell_Ghc_Typeclass_Type Families_Deriving - Fatal编程技术网

Haskell DeriveAnyClass与空实例

Haskell DeriveAnyClass与空实例,haskell,ghc,typeclass,type-families,deriving,Haskell,Ghc,Typeclass,Type Families,Deriving,假设我有一个类型族,如果传递给它的类型不是记录,它会在编译时抛出一个自定义类型错误: type系列IsRecord(a::type)其中 ... 现在,我有了这个类型类,它有默认实现的方法,但通过添加IsRecord约束,要求该类型是记录: class IsRecord a=>Foo a其中 foo::Text foo=“foo” 当试图错误地使用它时,如果我们将其作为非记录类型的常规实例使用,它将成功编译失败: data Bar=Bar 实例Foo Bar--错误:Bar不是记录 但是如

假设我有一个类型族,如果传递给它的类型不是记录,它会在编译时抛出一个自定义类型错误:

type系列IsRecord(a::type)其中
...
现在,我有了这个类型类,它有默认实现的方法,但通过添加
IsRecord
约束,要求该类型是记录:

class IsRecord a=>Foo a其中
foo::Text
foo=“foo”
当试图错误地使用它时,如果我们将其作为非记录类型的常规实例使用,它将成功编译失败:

data Bar=Bar
实例Foo Bar--错误:Bar不是记录
但是如果我启用
-xderivanyclass
并将其添加到派生子句中,这不会导致编译失败,完全忽略约束:

data Bar=Bar
派生(Foo)
我知道,
DeriveAnyClass
生成一个空实例声明,这就是我在第一个示例中所做的,但它仍然不会抛出错误。发生什么事了


我正在使用GHC 8.6.4

哇!我本打算将此标记为的副本,但似乎GHC的行为自该问题被问到和回答后发生了变化

无论如何,如果您在启动ghci之前用ghci内部的
:i
或用
-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手册中关于它的内容,尽管我怀疑其中的描述不是很精确就是不完整,因为如果我严格遵守文档中规定的规则,我不会得到编译器在这里给出的相同答案。(我怀疑真正的答案是,它首先编写实例,然后执行通常的类型推断操作,并将以这种方式发现的任何约束复制到实例上下文中。)

它将“继承”约束,如
instance IsRecord Bar=>Foo Bar
。是的,但这不应该编译,对吗?为什么不?约束是错误的,但这不是问题。如果您稍后在使用该实例的模块中添加该实例,则该实例将变为“可用”。我知道实际上这不是问题,但我的问题是这两件事之间的区别。您只需说如果
IsRecord Bar
保持不变,然后我们可以定义一个
实例Foo Bar
,如该实例中指定的那样。因为现在该约束不成立,如果稍后添加实例(例如在另一个模块中),则该约束为true,因此您将获得一个实例。因此,它增加了额外的灵活性。