将任意类约束“C a”转换为“C a Bool”

时间:2014-12-05 11:34:28

标签: haskell typeclass

因此,C a Bool形式的类型类有许多优点。主要是因为当正常C a隐式地对所有内容进行AND时,它们允许您在两个约束之间进行任何逻辑运算。

如果我们考虑~类约束,可以这样做

class Equal x y b | x y -> b
instance Equal x x True
instance False ~ b => Equal x y b

但是,这个案例的特殊之处在于,将x x放在实例的头部相当于头部中的x ~ y =>然后x y。任何其他类型类都不是这种情况。 因此,如果我们尝试为类C执行类似操作,我们会得到类似

的内容
class C' x b | x -> b
instance C x => C' x True
instance False ~ Bool => C' x b

不幸的是,这不起作用,因为只会选择其中一个实例,因为它们不会区分类型x,所以任何类型都匹配两个头。

我还阅读了https://www.haskell.org/haskellwiki/GHC/AdvancedOverlap,它再次不适用于任何类C,因为它要求您重写原始类的所有实例。理想情况下,我希望我的代码可以与GHC.Exts.ConstraintKindSignatures一起使用,以便C可以参数化。

所以,对于像这样的课程

class Match (c :: * -> Constraint) x b | c x -> b

我如何编写实例,以便Match c x True当且仅当c xMatch c x False时才会这样做?

1 个答案:

答案 0 :(得分:1)

由于所谓的开放世界假设,这在Haskell中是不可能的。它声明类型类的实例集是打开的,这意味着您可以随时创建新实例(而不是封闭的世界,其中必须有一组固定的实例)。例如,虽然在Prelude中定义了Functor类型类,但我仍然可以在我自己的代码中为它创建实例,而不是在Prelude中。

为了实现您提出的建议,编译器需要一种方法来检查类型T是否是类C的实例。但是,这需要编译器知道该类的所有可能实例,并且由于开放世界的假设而无法实现(在编译Prelude时,编译器仍然知道您以后会生成{{1}也是YourOwnFunctor的一个实例。

使其工作的唯一方法是仅考虑当前可见的实例(因为它们是在当前模块或其任何导入中定义的)。但这会导致非常不可预测的行为:可见实例集不仅取决于模块的导入,还取决于导入的导入,因为您无法隐藏实例。因此,代码的行为将取决于依赖项的实现细节。

如果你想要一个封闭的世界,你可以使用GHC 7.8中引入的closed type families。使用它们,你可以写:

Functor