Haskell - flip arguments of a typeclass with two parameters

◇◆丶佛笑我妖孽 提交于 2020-04-14 05:44:12

问题


I have a multiparam typeclass which supplies a function that makes sense to have its arguments swapped:

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

So if a and b form Swappable a b, then b and a should form Swappable b a. Writing a swapped instance for each normal instance would be a chore, so I naively wrote

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

Which doesn't compile with the following error:

    • 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
   |                           ^^^^^^^^^^^^^

Now, I'm not really averse to turning on FlexibleInstances, but I don't understand why I need it in the first place. All type variables there appear once, and are all distinct. So why do I get this error?


回答1:


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

Means that your instance must be of the form

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

where T and U are type constructors. Without that extension, you can not have only single variables a and b without a constructor on top.

FlexibleInstances is harmless, anyway, and should arguably turned on by default. Maybe a future revision of the Haskell Report will include it.

I would be far more concerned by the overlapping, instead. instance Swappable b a => Swappable a b will overlap with any other instance. It will also require undecidable instances. I'm not sure about what you are trying to achieve is a good idea.




回答2:


In this case, you can write the following:

{-# LANGAUGE UndecidableSuperClasses #-} -- 2
class Swappable b a => Swappable a b where -- 1
      swappable :: a -> b -> Bool
      swappable = flip swappable -- 3

(1) makes it so that, if you know that a and b are Swappable, then you also know that b and a are Swappable. That is,

swappable' :: Swappable a b => b -> a -> Bool
swappable' = swappable

compiles, even though the argument order seems "wrong", because the Swappable a b constraint itself implies Swappable b a, and it is that implementation that the swappable call chooses.

(2) makes GHC stop complaining about the recursive superclass on Swappable. This is a recent feature, introduced in GHC 8.0.1. Note that we don't need FlexibleInstances (though it's harmless) or UndecidableInstances (which is mostly OK) or OverlappingInstances (which sets the klaxons blaring). UndecidableSuperClasses probably falls in between the first two on the "danger" scale.

(3) is the default implementation of swappable. You can make that whatever you like. Usage of this class proceeds as follows:

instance Swappable Bool Int where
  swappable _ 0 = False
  swappable True n = n > 0
  swappable False n = n < 0
instance Swappable Int Bool where -- program does not compile if this is missing

instance Eq a => Swappable a a where swappable = (==)

The Swappable Int Bool class has, as superclass, Swappable Bool Int, so its swappable can be defined in terms of that superclass. Swappable Bool Int contains the logic. If one of the instances were missing, then the other instance's superclass constraint would be unfulfilled, so the program wouldn't compile. In the Swappable a a case, the instance is its own "superinstance". (It does require FlexibleInstances, but the reason is orthogonal to our purposes.)

These all work:

> swappable 5 5 -- defaulted to Integer, mind you
True
> swappable True (5 :: Int)
True
> swappable (5 :: Int) False
False
> swappable' (0 :: Int) True
False


来源:https://stackoverflow.com/questions/51221528/haskell-flip-arguments-of-a-typeclass-with-two-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!