我像这样制作了一个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)’
有关如何使其工作的任何想法?或者如果有必要,可能还有更好的设我想我可能只需要明确指出要采取哪种转换方式。
答案 0 :(得分:4)
我认为这需要UndecidableInstances
:
instance (Convertible a b, Convertible b c) => Convertible a c where
鉴于a
,由于函数依赖性,我们可以计算b
。但是,我无法保证b
比a
更小/更简单!它可以是例如那个b ~ [[a]]
,在这种情况下,我们减少了检查Convertible a c
以检查Convertible [[a]] c
的问题。在实例搜索期间,这很容易导致不终止,因为类参数没有减少。
相关说明:如果您满足功能依赖性,则只能转换b
的{{1}}类型a
。在这种情况下,为什么你需要传递性?没有别的a
可以转换为。换句话说,在传递性情况下,您需要c ~ b
,或者您a
确定b
和c
,这违反了功能依赖性。 (毕竟我猜你真的不想要功能依赖。)
无关的注意事项:还要注意例如重叠 - 上面的例子看起来很麻烦。您可能还必须使用OverlappingInstances
和/或IncoherentInstances
,这两种情况都会导致令人头疼。