我正在尝试编写不安全Enum
函数的完整版本:
predMay :: Enum a => a -> Maybe a
succMay :: Enum a => a -> Maybe a
toEnumMay :: Enum a => Int -> Maybe a
我的问题是,如果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)
我必须得到我想要的功能的最好的想法是使用另一个类型类:
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
但这导致了对Duplicate instance declarations
的抱怨。
我在这里有正确的想法,还是有更好的方法来解决这个问题?还有其他人已经这样做了吗? (我知道包prelude-safeenum},但Enum
对我来说的主要优势是我们可以deriving
它。)这些安全功能是否可行,或{{1}在野外太毛茸茸,不能让这么简单的解决方案安全吗?
答案 0 :(得分:5)
这不可能。请记住,Haskell类型类是 open 。您的提案需要根据类型是否属于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
...