Haskell 为什么';当数字常数超出范围时,GHC投诉
GHC默默地忽略数值常量中超出范围的位 这种行为让我今天与一只相当奇怪的虫子搏斗:Haskell 为什么';当数字常数超出范围时,GHC投诉,haskell,Haskell,GHC默默地忽略数值常量中超出范围的位 这种行为让我今天与一只相当奇怪的虫子搏斗: [0..256]::[Word8] -- evaluates to [0]! 我知道是什么导致了这个错误(在rot256世界中256==0)。。。。我感兴趣的是为什么GHC/Haskell在编译时不抱怨它 (这种行为对于Int也是如此——例如,18446744073709551617::Int=1) 我已经习惯于Haskell捕捉琐碎的编译时问题,当我不得不追踪到这一点时,我感到惊讶。这取决于单个Num实例的实
[0..256]::[Word8] -- evaluates to [0]!
我知道是什么导致了这个错误(在rot256世界中256==0)。。。。我感兴趣的是为什么GHC/Haskell在编译时不抱怨它
(这种行为对于Int也是如此——例如,18446744073709551617::Int=1
)
我已经习惯于Haskell捕捉琐碎的编译时问题,当我不得不追踪到这一点时,我感到惊讶。这取决于单个
Num
实例的实现。如果你表现出色
> :type 1
1 :: Num a => a
因此,Haskell只在最初将某些内容转换为泛型Num
,然后指定一种Word8
类型。如果你尝试
> (maxBound :: Word8) + 1
0
> maxBound :: Word8
255
这就是所谓的溢出,在许多语言中都是如此,特别是C.Haskell并没有阻止您这样做,因为在某些合法的情况下,您可能希望溢出。相反,由程序员来确保输入数据的有效性。此外,正如jozefg指出的,在编译时不可能知道每个转换是否有效
如果已经有
Eq
、Bounded
和Enum
,则可以实现一个Cyclic
类,该类为您提供所需的行为:
class (Eq a, Bounded a, Enum a) => Cyclic a where
next :: a -> a
next a = if a == maxBound then minBound else succ a
prev :: a -> a
prev a = if a == minBound then maxBound else pred a
instance Cyclic Word8
> next 255 :: Word8
0
> prev 0 :: Word8
255
幸运的是,对于所有的
Integral
类型,您已经有了Enum
和Eq
,而我所知道的唯一没有有界的Integral
是Integer
。这只是为您想要使用的每一个添加实例循环的问题。我怀疑诚实的答案是“因为还没有人实现它”。但我认为答案还有另一层,那就是存在一些微妙的设计问题
例如:我们如何知道256
超出了Word8
的范围?好吧,我想一个答案可能是编译器可能会注意到Word8
是Integral
、Ord
和Bounded
三者的实例。所以它可以生成一个类似
(256 :: Integer) > fromIntegral (maxBound :: Word8)
并在编译时评估此检查。问题是,突然之间,我们在编译时运行潜在的用户编写的代码(例如,maxBound
、frompintegral
、和(>)
),这些代码可能都来自程序员可以编写的实例声明)。这可能有点危险——因为不可能知道我们是否会得到答案!所以,至少您希望在默认情况下关闭此检查,并且想必至少和模板Haskell一样难以打开
另一方面,也可以只构建一些我们“信任”的实例——如您所说的Word8
和Int
。我会发现这有点令人失望,尽管这样的补丁可能不会被拒绝。我肯定很熟悉溢出情况。。。。我只是不想在哈斯克尔处理这件事。如果我想使用rot数,我希望它们有一个单独的类型,比如Rot8,其中(255:Rot8)+(1::Rot8)=(0::Rot8)
,甚至可以说(256::Rot8)=(0:Rot8)
@jamshidh自然(无符号)整数之类的东西呢?它们是一个相当常见的用例(索引),但您很少直接使用它们。相反,更常见的做法是在使用之前确保索引在适当的范围内,或者使用一个返回的索引函数,可能是一个值。这基本上是同一个问题。实际上,您可以创建一个循环的
类,该类将按照您的意愿工作,它取决于有界的
和枚举
,但实现起来非常简单。我也喜欢其他人所说的,但我将答案授予您,因为这个答案最接近我当前对这一提议的更改的观点,这是-这是可能的,这将是好的。。。。这很难正确。只是出于好奇,GHC这种特殊情况下的行为是否只对文字有效,或者编译器无法获得这些信息?@GabrielGonzalez我很确定我在回答中所说的一切都适用,即使我们只对文字感兴趣。@DanielWagner你能澄清一下吗?检查数字文本如何涉及比保证终止的单个比较操作更复杂的内容?你能举一个可能出错的例子吗?请注意,我假设maxBound
是静态已知的(即,您为其实现的类型集是静态的)。@GabrielGonzalez在我的回答中提到:所有from integral
、(>)
)和maxBound
都是用户编写的代码,因此它们都可以发散。“rot256”我猜您的意思是“mod 256”. ;-)