Мы можем уменьшить это
GHCi> toTwosComp (1 :: Word8)
*** Exception: divide by zero
Обратите внимание, что это работает, если вы используете Word16, Int, Integer, или любое количество типов, но терпит неудачу при использовании Word8 как B.unpack
дает нам! Так почему это терпит неудачу? Ответ находится в source code до Codec.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
, в процессе его базового преобразования, делит на используемую базу, поэтому он заканчивается делением на ноль, создавая поведение, которое вы получаете.
Какое решение? Преобразование Word8s в Ints с fromIntegral
перед передачей их toTwosComp
:
convert :: B.ByteString -> [Octet]
convert = map convert' . B.unpack
where convert' b = head $ toTwosComp (fromIntegral b :: Int)
Лично это поведение беспокоит меня немного, и я думаю, что toTwosComp
, вероятно, следует сделать такое само преобразование, вероятно в целое, так что он работает с интегральные типы каждого размера; но это повлечет за собой штраф за производительность, который разработчикам может не понравиться. Тем не менее, это довольно запутанный провал, который требует понимания источника. К счастью, очень легко обойти.
Это ошибка в 'toTwosComp'. – augustss