2011-12-17 45 views
16

我有一個小的Haskell程序,爲什麼零異常的鴻溝,當我運行它(GHC 7.0.3)這段代碼爲什麼被零除?

import qualified Data.ByteString.Lazy as B 
import Codec.Utils 

convert :: B.ByteString -> [Octet] 
convert bs = map (head . toTwosComp) $ B.unpack bs 

main = putStrLn $ show $ convert $ B.pack [1, 2, 3, 4] 

誰能幫助我明白這是怎麼回事就被扔到很好奇?

+2

這是'toTwosComp'中的一個錯誤。 – augustss

回答

17

使用Word8時,我們可以將此減少

GHCi> toTwosComp (1 :: Word8) 
*** Exception: divide by zero 

請注意,這個工程如果使用WORD16,INT,整型,或任意數量的類型,但是失敗了,因爲B.unpack給我們!那爲什麼它會失敗?答案見於source codeCodec.Utils.toTwosComp。您可以看到它調用toBase 256 (abs x),其中x是參數。

toBase類型 - 不是從Codec.Utils模塊導出,並且沒有在源一個明確的類型簽名,但你可以把定義在一個文件中,並要求GHCI是什麼類型看這個(:t toBase) ,是

toBase :: (Integral a, Num b) => a -> a -> [b] 

因此,明確註釋類型,toTwosComp呼籲toBase (256 :: Word8) (abs x :: Word8)。什麼是256 :: Word8

GHCi> 256 :: Word8 
0 

哎呀! 256> 255,所以我們不能把它放在Word8中,它會默默地溢出。 toBase,在其基數轉換過程中,除以所使用的基數,所以它最終除以零,產生你所得到的行爲。

解決方案是什麼?它們傳遞給toTwosComp之前fromIntegral轉換Word8s到INTS:

​​

就個人而言,這種行爲讓我擔心了一下,我覺得toTwosComp也許應該做這樣的轉換本身,可能整數,以便它的工作原理每種尺寸的整數類型;但是這會招致開發者可能不喜歡的性能損失。不過,這是一個令人困惑的失敗,需要潛水員理解。謝天謝地,這很容易解決。

+0

超好玩!非常感謝:D – Litherum

5
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] 

它的工作原理!