我有一个多参数类型类,它提供了一个有意义的函数,可以将其参数互换:

class Swappable a b where
    swappable :: a -> b -> Bool


因此,如果ab形成Swappable a b,则ba应该形成Swappable b a。为每个普通实例编写一个交换实例会很麻烦,所以我天真地写道

instance Swappable a b => Swappable b a where
    swappable b a = swappable a b


不会编译并显示以下错误:

    • Illegal instance declaration for ‘Swappable b a’
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are *distinct type variables*,
         and each type variable appears at most once in the instance head.
         Use FlexibleInstances if you want to disable this.)
    • In the instance declaration for ‘Swappable b a’
   |
12 | instance Swappable a b => Swappable b a where
   |                           ^^^^^^^^^^^^^


现在,我并不反对打开FlexibleInstances,但我不明白为什么我首先需要它。那里的所有类型变量都出现一次,并且都是不同的。那么,为什么会出现此错误?

最佳答案

All instance types must be of the form (T a1 ... an)


表示您的实例必须采用以下形式

instance Swappable (T a1 .. an) (U b1 .. bn) where ...


其中TU是类型构造函数。没有该扩展名,就不能只有一个变量ab,而没有顶部的构造函数。

无论如何,FlexibleInstances是无害的,并且可以说默认情况下应将其打开。也许Haskell报告的未来修订版将包含该报告。

相反,我会更担心重叠。 instance Swappable b a => Swappable a b将与任何其他实例重叠。它还将需要不确定的实例。我不确定您要达到的目标是一个好主意。

10-06 10:30