所以在C中有一个Bool形式的类型有很多优点.主要是因为它们允许您在两个约束之间进行任何逻辑运算,当正常的C只是隐含地将所有内容进行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.Constraint和KindSignatures一起使用,以便C可以参数化.
所以,这样一个类
class Match (c :: * -> Constraint) x b | c x -> b
如果且仅当c x,Match c x False时,如何编写实例才能使Match c x True?
解决方法
由于所谓的开放世界假设,这在哈斯克尔是不可能的.它指出,类型类的实例集是打开的,这意味着您可以随时创建新的实例(而不是封闭的世界,其中必须有一组固定的实例).例如,虽然Funlude类型在Prelude中定义,但我仍然可以在我自己的代码中为Prelude创建实例.
为了实现你的建议,编译器需要一种方法来检查类型T是否是类C的实例.然而,这需要编译器知道该类的所有可能的实例,这是不可能的,因为的开放世界假设(在编译Prelude时,编译器还不知道你以后使YourOwnFunctor成为Functor的一个实例).
使其工作的唯一方法是仅考虑当前可见的实例(因为它们在当前模块中定义或其任何导入).但是这将导致相当不可预测的行为:可见实例集不仅取决于模块的导入,还取决于导入导入,因为您无法隐藏实例.因此,您的代码的行为将取决于您的依赖关系的实现细节.
如果你想要一个封闭的世界,你可以使用closed type families,这是在GHC 7.8中引入的.使用它们,你可以写:
type family Equal a b :: Bool where Equal x x = True Equal x y = False