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