Declare a subclass with a complete definition

I am trying to do the following:

-- enum which wraps arround
class (Enum a, Bounded a) => CyclicEnum a where
    next, prev :: a -> a

-- for equatable types this is readily implemented
instance (Enum a, Bounded a, Eq a) => CyclicEnum a where
    next x | x == maxBound = minBound
           | otherwise     = succ x

    prev x | x == minBound = maxBound
           | otherwise     = pred x

But this doesn't compile unless I enable both FlexibleInstances and UndecidableInstances, which doesn't seem right. What is the proper way (ie, the generally used approach, preferably without language extensions) to do something like this? Is there one?


First off, there is nothing wrong at all with FlexibleInstances – it just disables a few restrictions of standard Haskell that are mostly there for historical reasons and perhaps for making compilers easier to write. But if you only use GHC – as almost everybody does – then there's no real reason not to use FlexibleInstances .

UndecidableInstances is more debatable, but there are some cases where it's definitely ok to use that too.

However, in your example, I don't see the need to define any new type class at all! Why not just define, as free functions,

next, prev :: (Enum a, Bounded a, Eq a) => a -> a
next x | x == maxBound = minBound
       | otherwise     = succ x
prev x | x == minBound = maxBound
       | otherwise     = pred x

Well. Probably your intention was to also add other instances for CyclicEnum , apart from the generic one. But that's actually not possible! Even with UndecidableInstances . It needs OverlappingInstances (or rather, Overlappable pragmas), but overlapping instances are really not something you should use just because you can.


你也可以使用默认签名来得到你所要求的:一个默认的实现只有equatable类型(虽然@ leftaroundabout的答案可能会更好的这种特定情况)。

class (Enum a, Bounded a) => CyclicEnum a where
    next, prev :: a -> a
    default next, prev :: Eq a => a -> a

    next x | x == maxBound = minBound
           | otherwise     = succ x

    prev x | x == minBound = maxBound
           | otherwise     = pred x
链接地址: http://www.djcxy.com/p/43168.html

上一篇: 为什么GHC认为这个类型变量不是内射的?

下一篇: 用完整的定义声明一个子类