I'm trying to write total versions of the unsafe Enum functions:
predMay :: Enum a => a -> Maybe a
succMay :: Enum a => a -> Maybe a
toEnumMay :: Enum a => Int -> Maybe a
My problem is that the unsafe functions are only partial if the Enum is also Bounded, so safe versions should have a different form in the two cases:
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)
The best idea I've had to get the function I want is to use another typeclass:
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
but this causes a complaint about Duplicate instance declarations.
Do I have the right idea here, or is there a better way to approach this problem? Has someone else already done this? (I'm aware of the package prelude-safeenum, but the primary advantage of Enum for me is that we can deriving it.) Are these safe functions even possible, or are Enums in the wild too hairy to let such a simple solution be safe?
This cannot be done. Remember that Haskell type classes are open. Your proposal requires to do something different depending on whether or not a type belongs to the Bounded class. But you can never know a type doesn't belong to this class. (Well, you can know that e.g. Integer must not have a Bounded instance, but the compiler can not. Nothing stops you from defining a nonsense instance Bounded Integer where {minBound = 7; maxBound = 3} except common sense.)
The only reliable way to get the correct instances is to sort types manually in bounded-or-not. This can be done consisely enough, especially with a default:
class Enum a => SafeEnum a where
predMay :: a -> Maybe a
predMay = predMayUnboundedEnum
instance SafeEnum Integer
instance SafeEnum Rational
instance SafeEnum Int where predMay = predMayBoundedEnum
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With