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
Post a Comment