UndecidableInstances何时安全?关于GHC扩展的一些一般性问题

gsp*_*spr 13 haskell ghc

我知道-XUndecidableInstances的文档,但我想我要求详细说明.

假设我有两个多参数类型类(允许使用-XMultiParamTypeClasses)

class Foo a b
class Goo a b
Run Code Online (Sandbox Code Playgroud)

现在,假设我有一个参数化数据类型

data Bar a b
Run Code Online (Sandbox Code Playgroud)

我希望Foo在其中一个参数是其实例的一部分时创建一个实例Goo.我不确定前面的句子是否使用了完整的术语,所以这就是我想写的内容:

instance (Goo c d) => Foo d (Bar a d)
Run Code Online (Sandbox Code Playgroud)

没有UndecidableInstances延期,我不被允许.我认为这是因为实例没有引用c类型吗?

我是不是该...

  1. 只需启用扩展程序?有人可以详细说明它可以带给我什么样的麻烦?
  2. 添加另一个参数Foo,以便最后一个实例声明变成什么样的Foo c d (Bar a d)?这样做的一个问题是,我可能有其他实例Foo,从不对任何这样的"第四类型参数"进行任何引用(即instance Foo A B在我的代码的不相关部分中存在表单的实例),因此这些会破坏.我宁愿修理我的实例,而不是我的课程.
  3. 创建一个FooGoo具有足够参数的新类?在这种情况下,我觉得我在重复自己,但至少我不会打破无关的课程.

有没有人有任何智慧的话语?

bar*_*oap 10

我是否正确认为这是因为实例没有引用c类型?

是的,您的代码不符合(从此处):

对于上下文中的每个断言:没有类型变量在断言中出现的次数多于在头部中出现的次数

通常,除非您添加其他实例,否则它们应该是安全的,这些实例将形成一个循环.事情只会变得非常毛茸茸(和编译器相关)OverlappingInstances,当你走的时候就会变得邪恶IncoherentInstances.

如果你不了解你想要完成什么,就很难给出合理的设计建议,但首先要检查的是你是否真的需要将c作为Goo的参数.您可以像这样表达您想要完成的事情:

class Goo d where
    bar :: d c -> Int
    baz :: Quux c => d c -> Int
Run Code Online (Sandbox Code Playgroud)

  • 我认为`Goo cd`约束会使`Foo d(Bar ad)`实例无法使用,除非`Goo`具有函数依赖性`d - > c` - 否则,编译器如何决定哪个'Goo`实例使用?如果所有`Goo`实例都有`c`作为'd`中没有出现的类型变量,那么@ barsoap建议删除该类型参数是要走的路. (2认同)