# How can I determine if one Enum value is the successor of another?

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

Solution

• Perhaps a more safe way to check this is making use of `enumFromTo`, and check if the second item of the list is the successor we are looking for. We can, like you say, simply pattern match on a list with two elements, we do not need to check if that second element is indeed `y`:

``````isSuccessorOf :: Enum a => a -> a -> Bool
isSuccessorOf y x
| [_,_] <- [x .. y] = True
| otherwise = False``````

or we can, like @chi says use this to look if there is a successor:

``````succMaybe :: Enum a => a -> Maybe a
succMaybe x = case [x ..] of
(_:z:_) -> Just z
_ -> Nothing``````