我如何确定一个Enum值是否是另一个Enum值的继承者?

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

看起来很合理。让我们尝试一下:

λ> 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

让我们再试一次:

λ> 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 Enums, 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

让我们尝试一下:

λ> 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 is new to GHC 8.10.1):

λ> import Data.Ord (Down(..))
λ> let delisleFreezing = Down 150
λ> isSuccessorOf (succ delisleFreezing) delisleFreezing
False

嗯,这不理想。

那么,没有这三个缺陷之一,有什么办法可以完成这项看似简单的任务?

  • 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