Haskell 为什么这个代码被零除?
我有一个小Haskell程序,我很好奇为什么在运行它时会抛出一个被零除的异常(GHC 7.0.3) 有人能帮我了解一下这里发生了什么吗?我们可以把它简化为Haskell 为什么这个代码被零除?,haskell,divide-by-zero,Haskell,Divide By Zero,我有一个小Haskell程序,我很好奇为什么在运行它时会抛出一个被零除的异常(GHC 7.0.3) 有人能帮我了解一下这里发生了什么吗?我们可以把它简化为 GHCi> toTwosComp (1 :: Word8) *** Exception: divide by zero 请注意,如果您使用Word16、Int、Integer或任意数量的类型,则此功能有效,但在使用Word8时失败,因为B.unpack为我们提供了!那么为什么它会失败呢?答案可在to中找到。您可以看到它调用了toBas
GHCi> toTwosComp (1 :: Word8)
*** Exception: divide by zero
请注意,如果您使用Word16、Int、Integer或任意数量的类型,则此功能有效,但在使用Word8时失败,因为B.unpack
为我们提供了!那么为什么它会失败呢?答案可在to中找到。您可以看到它调用了toBase 256(abs x)
,其中x是参数
toBase
的类型-不是从Codec.Utils模块导出的,并且在源代码中没有显式的类型签名,但是您可以通过将定义放入文件并询问GHCi类型(:t toBase
)来查看
因此,显式注释类型时,totwoscop
正在调用toBase(256::Word8)(abs x::Word8)
。什么是256::Word8
GHCi> 256 :: Word8
0
哎呀!256>255,所以我们无法将其保存在一个字8中,它会无声地溢出toBase
,在其基址转换过程中,被使用的基址除,因此它最终被零除,产生您得到的行为
解决办法是什么?在将单词8s传递到totwoscop
之前,使用from integral
将其转换为整数:
convert :: B.ByteString -> [Octet]
convert = map convert' . B.unpack
where convert' b = head $ toTwosComp (fromIntegral b :: Int)
就我个人而言,这种行为让我有点担心,我认为totwoscop
应该自己做这样的转换,很可能是整数,这样它就可以处理各种大小的整数类型;但这将导致性能损失,开发者可能不喜欢这种想法。不过,这是一个相当令人困惑的失败,需要源代码潜水才能理解。谢天谢地,这很容易解决
map (head . toTwosComp) [1, 2, 3, 4]
这段时间很好用
map (head . toTwosComp) $ B.unpack $ B.pack [1, 2, 3, 4]
导致您描述的异常。让我们看看有什么不同
> :t [1, 2, 3, 4]
[1, 2, 3, 4] :: Num t => [t]
> :t unpack $ pack $ [1, 2, 3, 4]
unpack $ pack $ [1,2,3,4] :: [Word8]
Word8可能是导致问题的原因。让我看看
> toTwosComp (1 :: Word8)
*** Exception: divide by zero
显然,我们必须将Word8转换为其他整数类型
> map (head . toTwosComp . fromIntegral) $ B.unpack $ B.pack [1, 2, 3, 4]
[1,2,3,4]
它起作用了 非常有帮助!非常感谢:D
> toTwosComp (1 :: Word8)
*** Exception: divide by zero
> map (head . toTwosComp . fromIntegral) $ B.unpack $ B.pack [1, 2, 3, 4]
[1,2,3,4]