多参数类型类和非法实例声明

时间:2015-12-16 17:44:33

标签: haskell typeclass

我像这样制作了一个Convertible类的版本:

class Convertible a b where
  convert :: a -> b

instance (Convertible a b, Functor f) => Convertible (f a) (f b) where
  convert = fmap convert

然而,我发现如果我想将两个转换串在一起,我将不得不创建一个新实例。所以我尝试添加这个:

instance (Convertible a b, Convertible b c) => Convertible a c where
  convert = convert . convert

编译器抱怨道:

Variable ‘b’ occurs more often than in the instance head
  in the constraint: Convertible a b
(Use UndecidableInstances to permit this)
In the instance declaration for ‘Convertible a c’
Variable ‘b’ occurs more often than in the instance head
  in the constraint: Convertible b c
(Use UndecidableInstances to permit this)
In the instance declaration for ‘Convertible a c’

此时我理解编译器为什么抱怨我,我真的不想打开UndecidableInstances。我目前设置实例的方式,每个a只有一个Convertible a b实例。我希望添加功能依赖a - > b会缓解这一点,但现在编译器正在抱怨仿函数实例:

Illegal instance declaration for ‘Convertible (f a) (f b)’
  The coverage condition fails in class ‘Convertible’
    for functional dependency: ‘a -> b’
  Reason: lhs type ‘f a’ does not determine rhs type ‘f b’
  Using UndecidableInstances might help
In the instance declaration for ‘Convertible (f a) (f b)’

有关如何使其工作的任何想法?或者如果有必要,可能还有更好的设我想我可能只需要明确指出要采取哪种转换方式。

1 个答案:

答案 0 :(得分:4)

我认为这需要UndecidableInstances

instance (Convertible a b, Convertible b c) => Convertible a c where

鉴于a,由于函数依赖性,我们可以计算b。但是,我无法保证ba更小/更简单!它可以是例如那个b ~ [[a]],在这种情况下,我们减少了检查Convertible a c以检查Convertible [[a]] c的问题。在实例搜索期间,这很容易导致不终止,因为类参数没有减少。

相关说明:如果您满足功能依赖性,则只能转换b的{​​{1}}类型a。在这种情况下,为什么你需要传递性?没有别的a可以转换为。换句话说,在传递性情况下,您需要c ~ b,或者您a确定bc,这违反了功能依赖性。 (毕竟我猜你真的不想要功能依赖。)

无关的注意事项:还要注意例如重叠 - 上面的例子看起来很麻烦。您可能还必须使用OverlappingInstances和/或IncoherentInstances,这两种情况都会导致令人头疼。