首页 > 解决方案 > 约束和资金解决方案

问题描述

我有一对 C1 和 C2 类,在 C1 上有一个fundep,如下所示:

class C1 a b | a -> b
class C2 a

我声明一个实例:

instance (C2 a) => C1 a T1

当我声明另一个实例时,我收到一个错误:

instance  C1 T2 T3
functional dependencies conflict between instance declarations:
  instance C2 a => C1 a T1
  instance C1 T2 T3

基本上,我打算将 T1 实例表示为:forall a where ais an instance ofC2 b isT1,只要T2不是C2.

GHC 将其理解为:foralla bT1,从而排除了将任何其他类型分配给b.

a我知道我可以通过包装来解决这个问题newtype,但这对我的应用程序来说很尴尬。

任何人都可以解释如何获得我想要的行为,如果确实可能的话,或者解释为什么不?

标签: haskellghctypeclassfunctional-dependenciestype-constraints

解决方案


您的实例在 FunDep 的“参数”位置重叠。这应该有效(未经测试):

{-# LANGUAGE GADTs, UndecidableInstances #-}

instance {-# OVERLAPPABLE #-} (C2 a, b ~ T1) => C1 a b

instance C1 T2 T3

这是在利用 GHC 的“虚假”FunDep 一致性检查。('bogus' 是 SPJ 编译器代码中的一个注释。)它不应该工作;这非常“作弊”;总有一天有人会修复它,上面的代码将停止工作。

OTOH 自 2008 年以来一直是威胁;它仍然没有得到解决;没有人(除了我)似乎有更好的建议。

以上没有实现的是你的

我的意思是T1实例的意思是:is 的实例forall a在哪里,只要不是 的实例,就允许另一个实例。aC2 bT1T2C2

但是你知道是否T2是一个实例C2——它是一个特定的类型(?)

如果您的意思是任何类型t2,我认为您需要重新表述这个问题。更高级的重叠和 FunDeps 可能是可行的——而且还有更多的虚假性。

考虑一个辅助类:

{-# LANGUAGE DataKinds #-}
class IsC2 a (t :: Bool) | a -> t

instance IsC2 T2 True

instance (t ~ False) => IsC2 a  t

instance IsC2 t2 True对于每个特定类型t2,您都需要一个C2.

instance (IsC2 a t, C1C2 t a T1 T3 b) => C1 a b

class C1C2 t a bt bf b  | t bt bf -> b
instance (C2 a) => C1C2 True  a bt bf bt   -- constraint as belt and braces
instance C1C2 False a bt bf bf

推荐阅读