Haskell中的安全和多态Enum

gil*_*mec 4 polymorphism enums haskell

我正在尝试编写不安全Enum函数的完整版本:

predMay :: Enum a => a -> Maybe a
succMay :: Enum a => a -> Maybe a
toEnumMay :: Enum a => Int -> Maybe a
Run Code Online (Sandbox Code Playgroud)

我的问题是不安全的函数只是部分,如果Enum也是Bounded,所以安全版本在两种情况下应该有不同的形式:

predMayUnboundedEnum :: Enum a => a -> Maybe a
predMayUnboundedEnum = Just . pred

predMayBoundedEnum :: (Enum a, Bounded a) => a -> Maybe a
predMayBoundedEnum x
  | fromEnum x == fromEnum (minBound `asTypeOf` x) = Nothing
  | otherwise  = Just (pred x)
Run Code Online (Sandbox Code Playgroud)

我必须得到我想要的功能的最好的想法是使用另一个类型类:

class Enum a => SafeEnum a where
  predMay :: a -> Maybe a
instance Enum a => SafeEnum a where
  predMay = predMayUnboundedEnum
instance (Enum a, Bounded a) => SafeEnum a where
  predMay = predMayBoundedEnum
Run Code Online (Sandbox Code Playgroud)

但这引起了抱怨Duplicate instance declarations.

我在这里有正确的想法,还是有更好的方法来解决这个问题?还有其他人已经这样做了吗?(我知道包装prelude-safeenum,但Enum对我而言,主要的优点是我们可以deriving.)这些安全功能是否可行,或者是否Enum过于繁琐,让这样一个简单的解决方案安全?

lef*_*out 5

这是不可能做到的.请记住,Haskell类型类是开放的.您的提案需要根据类型是否属于Bounded该类来执行不同的操作.但你永远不会知道一个类型属于这个类.(嗯,可以知道,例如,Integer不能有一个Bounded实例,但编译器不能.没有什么能阻止你定义instance Bounded Integer where {minBound = 7; maxBound = 3}除常识之外的废话.)

获取正确实例的唯一可靠方法是在有界或无效中手动对类型进行排序.这可以很简单地完成,特别是默认情况下:

class Enum a => SafeEnum a where
  predMay :: a -> Maybe a
  predMay = predMayUnboundedEnum

instance SafeEnum Integer
instance SafeEnum Rational
instance SafeEnum Int where predMay = predMayBoundedEnum
...
Run Code Online (Sandbox Code Playgroud)