haskell - show returning wrong value when used with unsafeCoerced value -


i experimenting unsafecoerce int8 , word8, , found surprising behaviour (for me anyway).

word8 8 bit unsigned number ranges 0-255. int8 signed 8 bit number ranges -128..127.

since both 8 bit numbers, assumed coercing 1 safe, , return 8 bit values if signed/unsigned.

for example, unsafecoerce (-1 :: int8) :: word8 expect result in word8 value of 255 (since bit representation of -1 in signed int same 255 in unsigned int).

however, when perform coerce, word8 behaviour strange:

> ghci, version 7.4.1: http://www.haskell.org/ghc/  :? > import data.int > import data.word > import unsafe.coerce > class showtype typename :: -> string > instance showtype int8 typename _ = "int8" > instance showtype word8 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 

i don't understand how show x returning "-1" here. if @ map show [minbound..maxbound :: word8], no possible value word8 results in "-1". also, how adding 0 number change behaviour, if type isn't changed? strangely, appears show class affected - showtype class returns correct value.

finally, code fromintegral (-1 :: int8) :: word8 works expected, , returns 255, , works correctly show. is/can code reduced no-op compiler?

note question out of curiosity how types represented in ghc @ low level. i'm not using unsafecoerce in code.

like @kosmikus said, both int8 , int16 implemented using int#, 32 bit-wide on 32-bit architectures (and word8 , word16 word# under hood). this comment in ghc.prim explains in more detail.

so let's find out why implementation choice results in behaviour see:

> let x = unsafecoerce (-1 :: int8) :: word8 > show x "-1" 

the show instance word8 is defined as

instance show word8     showsprec p x = showsprec p (fromintegral x :: int) 

and fromintegral frominteger . tointeger. definition of tointeger word8 is

tointeger (w8# x#)            = smallinteger (word2int# x#) 

where smallinteger (defined in integer-gmp) is

smallinteger :: int# -> integer smallinteger = s# 

and word2int# primop type word# -> int# - analog of reinterpret_cast<int> in c++. explains why see -1 in first example: value reinterpreted signed integer , printed out.

now, why adding 0 x give 255? looking @ num instance word8 see this:

(w8# x#) + (w8# y#)    = w8# (narrow8word# (x# `plusword#` y#)) 

so looks narrow8word# primop culprit. let's check:

> import ghc.word > import ghc.prim > case x of (w8# w) -> (w8# (narrow8word# w)) 255 

indeed is. explains why adding 0 not no-op - word8 addition clamps down value intended range.


Comments

Popular posts from this blog

monitor web browser programmatically in Android? -

Shrink a YouTube video to responsive width -

wpf - PdfWriter.GetInstance throws System.NullReferenceException -