2011-12-17 13 views
16

मैं एक छोटे से हास्केल प्रोग्राम है, और उत्सुक हूँ क्यों शून्य अपवाद द्वारा विभाजन फेंक दिया जाता है जब मैं यह (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 इंट, पूर्णांक, या प्रकार के किसी भी संख्या का उपयोग करें, लेकिन विफल रहता है यह कम कर सकते हैं, के रूप में 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] 

तो है प्रकार स्पष्ट रूप से व्याख्या, toTwosComptoBase (256 :: Word8) (abs x :: Word8) बुला रहा है। 256 :: Word8 क्या है?

GHCi> 256 :: Word8 
0 

ओह! 256> 255, इसलिए हम इसे Word8 में नहीं रोक सकते हैं, और यह चुपचाप बहती है। toBase, अपने मूल रूपांतरण की प्रक्रिया में, आधार का उपयोग करके विभाजित होता है, इसलिए यह आपके द्वारा प्राप्त किए जा रहे व्यवहार का उत्पादन करके शून्य से विभाजित होता है।

समाधान क्या है? उन्हें toTwosComp को पार करने से पहले fromIntegral साथ Ints को Word8s कन्वर्ट:

convert :: B.ByteString -> [Octet] 
convert = map convert' . B.unpack 
    where convert' b = head $ toTwosComp (fromIntegral b :: Int) 

व्यक्तिगत रूप से, इस व्यवहार मुझे थोड़ी चिंता है, और मैं, लगता है toTwosComp शायद इस तरह के एक रूपांतरण ही है, पूर्णांक की संभावना क्या करना चाहिए, ताकि यह साथ काम करता है प्रत्येक आकार के अभिन्न प्रकार; लेकिन यह एक प्रदर्शन जुर्माना होगा कि डेवलपर्स के विचार को पसंद नहीं हो सकता है। फिर भी, यह एक बहुत भ्रमित विफलता है जिसके लिए स्रोत-डाइविंग को समझने की आवश्यकता है। शुक्र है, चारों ओर काम करना बहुत आसान है।

+0

सुपर सहायक! बहुत बहुत धन्यवाद: डी – 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] 

यह काम करता है!

संबंधित मुद्दे