如何确定一个Enum值是否是另一个Enum值的继承者? [英] How can I determine if one Enum value is the successor of another?

查看:135
本文介绍了如何确定一个Enum值是否是另一个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

看起来很合理.试试吧:

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

哇.那应该是False.确保我们不要尝试执行succ 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)

嗯,现在它仅适用于有界类型.我想避免对无界和有界的Enum分别使用一个函数,尤其是在编译时没有任何事情可以阻止您在有界类型上使用无界函数的情况下.让我们改用Ord约束:

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

但是现在我做了一个毫无根据的假设.让我们再尝试一件事(注意:这取决于Down具有一个Enum实例,这对GHC 8.10.1是新的):

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

那不理想.

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

So is there any way to do this seemingly-simple task, without one of these three flaws?

  • 无法为非Bounded
  • 的类型进行编译
  • Bounded
  • 类型的底部
  • succ x > x不成立的类型给出错误的答案
  • 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

推荐答案

也许更安全的方法是使用 enumFromTo ,然后检查列表的第二项是否是我们要查找的后继项.我们可以像

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

这篇关于如何确定一个Enum值是否是另一个Enum值的继承者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆