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?
Bounded
Bounded
succ x > x
doesn't holdThere are two ways for making comparison of enum members : By using == operator By using equals () method
In Java, enum is a special Java type used to define collections of constants. More precisely, a Java enum type is a special kind of Java class. An enum can contain constants, methods etc. enum can be defined as a group of named constant. equals method uses == operator internally to check if two enum are equal.
Instead of returning null or empty Optional value, we may want to throw an exception. Which exception to throw totally depends on the needs of the system. We'll choose to throw an IllegalArgumentException if we don't find the enum. Here's the code for the search method:
It's up to us how we treat the not-found scenario. One option is that we can return a default enum value. Conversely, we can throw an exception. We'll see more examples of searching the enum shortly. Now let's test our search logic. First, the positive scenario:
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
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