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

我正在尝试执行以下操作:

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

但是,除非启用FlexibleInstances和UndecidableInstances,否则不会编译,这似乎不正确。 什么是正确的方式(即,通常使用的方法,最好是没有语言扩展)来做这样的事情? 有一个吗?


首先,对于FlexibleInstances没有任何问题 - 它只是禁用了标准Haskell的一些限制,这些限制大多是出于历史原因,并且可能使编译器更容易编写。 但是如果你只使用GHC--就像几乎所有人一样 - 那么没有真正的理由不使用FlexibleInstances

UndecidableInstances更具争议性,但有些情况下也可以使用它。

然而,在你的例子中,我没有看到需要定义任何新类型的类! 为什么不直接定义为免费功能,

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

好。 可能你的意图是为CyclicEnum添加其他实例,除了通用的。 但那实际上是不可能的! 即使使用UndecidableInstances 。 它需要OverlappingInstances (或者说Overlappable pragmas),但是重叠的实例并不是你应该使用的东西,因为你可以。


你也可以使用默认签名来得到你所要求的:一个默认的实现只有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/43167.html

上一篇: Declare a subclass with a complete definition

下一篇: is Haskell a managed language?