I'm trying to write a function that tells me whether one Enum
is the successor of another. Here was my first attempt:
isSuccessorOf x y = x == succ y
Looks reasonable. Let's try it:
λ> isSuccessorOf 3 2
True
λ> isSuccessorOf 1 5
False
λ> isSuccessorOf 3 (maxBound :: Int)
*** Exception: Prelude.Enum.succ{Int}: tried to take `succ' of maxBound
Whoops. That should have been False
. Let's make sure we don't try to do succ maxBound
:
isSuccessorOf x y = y /= maxBound && x == succ y
Let's try it again:
λ> isSuccessorOf 3 (maxBound :: Int)
False
λ> isSuccessorOf 3 (2 :: Integer)
<interactive>:2:1: error:
• No instance for (Bounded Integer)
arising from a use of ‘isSuccessorOf’
• In the expression: isSuccessorOf 3 (2 :: Integer)
In an equation for ‘it’: it = isSuccessorOf 3 (2 :: Integer)
Hmm, now it only works on bounded types. I'd like to avoid needing a separate function for unbounded and bounded Enum
s, especially if there's nothing at compile-time to keep you from using the unbounded function on a bounded type. Let's use an Ord
constraint instead:
isSuccessorOf x y = x > y && x == succ y
And let's try it:
λ> isSuccessorOf 3 (maxBound :: Int)
False
λ> isSuccessorOf 3 (2 :: Integer)
True
But now I'm making an unwarranted assumption. Let's try one more thing (note: this depends on Down
having an Enum
instance, which it only has in GHC 8.10):
λ> import Data.Ord (Down(..))
λ> let delisleFreezing = Down 150
λ> isSuccessorOf (succ delisleFreezing) delisleFreezing
False
Well that's less than ideal.
So is there any way to do this seemingly-simple task, without one of these three flaws?
- Fails to compile for types that aren't
Bounded
- Bottoms for types that are
Bounded
- Gives the wrong answer for types where
succ x > x
doesn't hold
fromEnum
to map it onInt
s, but this is in fact also one of the "weak spots" of theEnum
imho: that not all values per se fit in theInt
range :( – TrippenumFrom
is better, since we can then just do pattern matching on the list. – Trippsucc $ Data.Ord.Down 150
? – RevolverDown 151
– IneducationsuccMaybe x = case [x..] of (_:z:_) -> Just z ; _ -> Nothing
. You should write an answer. – Distance