2013-04-05 6 views
5

मैं unsafeCoerce के साथ Int8 और Word8 के साथ प्रयोग कर रहा था, और मुझे कुछ आश्चर्यजनक व्यवहार (वैसे भी मेरे लिए) मिला।असुरक्षित मूल्य के साथ उपयोग किए जाने पर गलत मान लौटाते हुए

Word8 एक 8 बिट हस्ताक्षरित संख्या है जो 0-255 से है। Int8 एक हस्ताक्षरित 8 बिट संख्या है जो -128..127 से है।

चूंकि वे 8 बिट संख्याएं हैं, इसलिए मुझे लगता है कि एक दूसरे को एक दूसरे से जोड़ना सुरक्षित होगा, और केवल 8 बिट मानों को वापस कर दें जैसे कि यह हस्ताक्षरित/हस्ताक्षरित था।

उदाहरण के लिए, unsafeCoerce (-1 :: Int8) :: Word8 मैं 255 के एक Word8 मूल्य में परिणाम की उम्मीद होती है (एक हस्ताक्षरित पूर्णांक में -1 की बिट प्रतिनिधित्व के बाद से 255 के रूप में ही एक अहस्ताक्षरित int में है)।

हालांकि, जब मैं मजबूर प्रदर्शन करते हैं, Word8 व्यवहार अजीब है:

> GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help 
> import Data.Int 
> import Data.Word 
> import Unsafe.Coerce 
> class ShowType a where typeName :: a -> String 
> instance ShowType Int8 where typeName _ = "Int8" 
> instance ShowType Word8 where typeName _ = "Word8" 

> let x = unsafeCoerce (-1 :: Int8) :: Word8 
> show x 
"-1" 
> typeName x 
"Word8" 
> show (x + 0) 
"255" 
> :t x 
x :: Word8 
> :t (x + 0) 
(x + 0) :: Word8 

मुझे समझ नहीं आता कैसे show x"-1" यहां लौटा रहा है। यदि आप map show [minBound..maxBound :: Word8] देखते हैं, तो Word8 के लिए कोई संभावित मूल्य "-1" में परिणाम नहीं है। साथ ही, संख्या में 0 जोड़ना व्यवहार को कैसे बदलता है, भले ही प्रकार बदल नहीं गया हो? आश्चर्यजनक रूप से, यह भी प्रतीत होता है कि यह केवल Show वर्ग प्रभावित है - मेरा ShowType वर्ग सही मान देता है।

अंत में, कोड fromIntegral (-1 :: Int8) :: Word8 अपेक्षा के अनुसार काम करता है, और 255 देता है, और show के साथ सही ढंग से काम करता है। क्या यह कोड संकलक द्वारा नो-ऑप में कम किया जा सकता है?

ध्यान दें कि यह सवाल जिज्ञासा से बाहर है कि निम्न स्तर पर ghc में किस तरह का प्रतिनिधित्व किया जाता है। मैं वास्तव में अपने कोड में unsafeCoerce का उपयोग नहीं कर रहा हूँ।

उत्तर

10

तरह @kosmikus कहा, Int8 और Int16 दोनों एक Int#, का उपयोग करके लागू जो 32-बिट आर्किटेक्चर (और Word8 और Word16 हुड के नीचे Word# कर रहे हैं) पर 32 बिट चौड़ा है। जीएचसी.प्रिम में This comment अधिक विस्तार से बताते हैं।

तो चलो पता क्यों व्यवहार में इस कार्यान्वयन चुनाव परिणाम आप देखते हैं:

> let x = unsafeCoerce (-1 :: Int8) :: Word8 
> show x 
"-1" 

Show उदाहरण के लिए Word8is defined as

instance Show Word8 where 
    showsPrec p x = showsPrec p (fromIntegral x :: Int) 

और fromIntegral सिर्फ fromInteger . toInteger है।Word8 के लिए toInteger की परिभाषा

toInteger (W8# x#)   = smallInteger (word2Int# x#) 

वह जगह है जहाँ smallInteger (पूर्णांक-जीएमपी में परिभाषित)

smallInteger :: Int# -> Integer 
smallInteger i = S# i 

और word2Int# प्रकार Word# -> Int# के साथ एक primop है - सी में reinterpret_cast<int> की एक एनालॉग ++। तो यह बताता है कि आप पहले उदाहरण में -1 क्यों देखते हैं: मान को केवल एक हस्ताक्षरित पूर्णांक के रूप में पुन: परिभाषित किया गया है और मुद्रित किया गया है।

अब, 0 से x क्यों जोड़कर 255 दे? Word8 के लिए Num उदाहरण को देखते हुए हम इस देखें:

(W8# x#) + (W8# y#) = W8# (narrow8Word# (x# `plusWord#` y#)) 

तो यह narrow8Word# primop तरह लग रहा है दोषी है। आइए जांचें:

> import GHC.Word 
> import GHC.Prim 
> case x of (W8# w) -> (W8# (narrow8Word# w)) 
255 

वास्तव में यह है। यह बताता है कि क्यों 0 जोड़ना नो-ऑप नहीं है - Word8 अतिरिक्त वास्तव में इच्छित सीमा के मान को क्लैंप करता है।

+0

धन्यवाद यह अब सही समझ में आता है! –

4

आप यह नहीं कह सकते कि unsafeCoerce का उपयोग करने पर आप कुछ गलत हैं। यदि आप उस फ़ंक्शन का उपयोग करते हैं तो कुछ भी हो सकता है। कंपाइलर शायद एक शब्द में Int8 स्टोर करता है, और unsafeCoerce से Word8 का उपयोग करके इस शब्द में संग्रहीत किए गए आविष्कारों को तोड़ देता है। कनवर्ट करने के लिए fromIntegral का उपयोग करें।

Int8 से

रूपांतरण Word8fromIntegral उपयोग करने के लिए 86 पर एक GHC का उपयोग कर movzbl अनुदेश, जो मूल रूप से नो-सेशन है में बदल जाता है।

+0

मैं समझता हूं कि कुछ भी हो सकता है, लेकिन मुझे यह जानने में दिलचस्पी है कि हुड के नीचे क्या हो रहा है। जब तक 'वर्ड 8' हैकेल में उपयोग किए जाने पर 1 से अधिक बाइट का उपभोग नहीं करता है, तो मैं यह नहीं समझ सकता कि आप इस व्यवहार को 'असुरक्षित वाणिज्य' के साथ कैसे प्राप्त कर सकते हैं। 'लंबाई [मिनीबाउंड..मैक्सबाउंड :: वर्ड 8]' 256 है, बाइट में संयोजनों की एक ही संख्या है। तो कोई अवैध मूल्य कैसे हो सकता है? क्या हो रहा है यह देखने के लिए हैकेल में किसी मान के कच्चे मूल्य को डंप करने का कोई तरीका है? –

+3

जैसा कि लेनार्ट कहते हैं, एक शब्द में 'Int8' सबसे अधिक संग्रहीत किया जाता है। उदाहरण के लिए, 64-बिट मशीन पर मुझे 'शो' (असुरक्षित कॉमर्स (-1 :: इंट 8) :: वर्ड 32) '' के लिए '-1" 'मिल रहा है,' 'लेकिन' 18446744073709551615 "' शो के लिए (असुरक्षित वाणिज्य (- 1 :: Int8) :: वर्ड 64) '। – kosmikus

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

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