2011-12-17 4 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

我々はB.unpackが私たちを与えるとして、これは、あなたがWord16、INT、整数、または種類の任意の数を使用している場合は動作しますが、Word8を使用する際に失敗したことを

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

注意にこれを削減することができます!それでなぜ失敗するのですか?答えはsource codeCodec.Utils.toTwosCompにあります。 toBase 256 (abs x)が呼び出されます。xが引数です。

toBaseの種類 - Codec.Utilsモジュールから、ソースで明示的な型シグネチャなしでエクスポートができますが、ファイル内の定義を置くと型が何であるかをGHCiのを尋ねることによってこれを見ることができない(:t toBase) 、明示的なタイプの注釈付け、toTwosComptoBase (256 :: Word8) (abs x :: Word8)を呼び出している、だから、

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

です。 256 :: Word8とはなんですか?

GHCi> 256 :: Word8 
0 

おっと! 256> 255であるため、Word8で保持することはできず、黙ってオーバーフローします。 toBaseは、そのベース変換の過程で、使用されているベースで除算されるので、0で除算され、得られる動作が生成されます。

解決策は何ですか? toTwosCompに渡す前にfromIntegralでint型にWord8sを変換します

​​

は個人的に、この行動は私に少し心配、と私はそれがで動作するように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 

明らかに私たちは他の整数型に変換する必要があります。

> map (head . toTwosComp . fromIntegral) $ B.unpack $ B.pack [1, 2, 3, 4] 
[1,2,3,4] 

これは機能します。

関連する問題