如何确定一个枚举值是否是另一个枚举值的继承者?
How can I determine if one Enum value is the successor of another?
我正在尝试编写一个函数来告诉我一个 Enum
是否是另一个的继承者。这是我的第一次尝试:
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
哎呀。那应该是 False
。让我们确保我们不会尝试做 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)
嗯,现在它只适用于有界类型。我想避免为无界和有界 Enum
需要一个单独的函数,特别是如果在编译时没有任何东西可以阻止您在有界类型上使用无界函数。让我们改用 Ord
约束:
isSuccessorOf x y = x > y && x == succ y
让我们试试看:
λ> isSuccessorOf 3 (maxBound :: Int)
False
λ> isSuccessorOf 3 (2 :: Integer)
True
但现在我在做一个没有根据的假设。让我们再尝试一件事(注意:这取决于 Down
有一个 Enum
实例,它只在 GHC 8.10 中有):
λ> import Data.Ord (Down(..))
λ> let delisleFreezing = Down 150
λ> isSuccessorOf (succ delisleFreezing) delisleFreezing
False
嗯,这不太理想。
那么,有没有什么方法可以完成这个看似简单的任务,并且没有这三个缺陷之一?
- 无法为不是
Bounded
的类型编译
Bounded
类型的底部
- 对
succ x > x
不成立的类型给出错误答案
也许更安全的检查方法是使用 enumFromTo
, and check if the second item of the list is the successor we are looking for. We can, like ,只需对包含两个元素的列表进行模式匹配,我们不需要检查第二个元素是否确实是 y
:
isSuccessorOf :: Enum a => a -> a -> Bool
isSuccessorOf y x
| [_,_] <- [x .. y] = True
| otherwise = <b>False</b>
或者我们可以,比如 用这个来查看是否有继任者:
succMaybe :: Enum a => a -> Maybe a
succMaybe x = case <b>[x ..]</b> of
(_:z:_) -> Just z
_ -> Nothing
我正在尝试编写一个函数来告诉我一个 Enum
是否是另一个的继承者。这是我的第一次尝试:
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
哎呀。那应该是 False
。让我们确保我们不会尝试做 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)
嗯,现在它只适用于有界类型。我想避免为无界和有界 Enum
需要一个单独的函数,特别是如果在编译时没有任何东西可以阻止您在有界类型上使用无界函数。让我们改用 Ord
约束:
isSuccessorOf x y = x > y && x == succ y
让我们试试看:
λ> isSuccessorOf 3 (maxBound :: Int)
False
λ> isSuccessorOf 3 (2 :: Integer)
True
但现在我在做一个没有根据的假设。让我们再尝试一件事(注意:这取决于 Down
有一个 Enum
实例,它只在 GHC 8.10 中有):
λ> import Data.Ord (Down(..))
λ> let delisleFreezing = Down 150
λ> isSuccessorOf (succ delisleFreezing) delisleFreezing
False
嗯,这不太理想。
那么,有没有什么方法可以完成这个看似简单的任务,并且没有这三个缺陷之一?
- 无法为不是
Bounded
的类型编译
Bounded
类型的底部
- 对
succ x > x
不成立的类型给出错误答案
也许更安全的检查方法是使用 enumFromTo
, and check if the second item of the list is the successor we are looking for. We can, like y
:
isSuccessorOf :: Enum a => a -> a -> Bool
isSuccessorOf y x
| [_,_] <- [x .. y] = True
| otherwise = <b>False</b>
或者我们可以,比如
succMaybe :: Enum a => a -> Maybe a
succMaybe x = case <b>[x ..]</b> of
(_:z:_) -> Just z
_ -> Nothing