我正在用 Int8
和 Word8
尝试 unsafeCoerce
,并且发现了一些令人惊讶的行为(无论如何对我来说)。
Word8
是一个 8 位无符号数,范围为 0-255。 Int8
是一个有符号的 8 位数字,范围为 -128..127。
由于它们都是 8 位数字,我认为将一个数字强制转换为另一个数字是安全的,只需返回 8 位值,就好像它是有符号/无符号的一样。
例如,unsafeCoerce (-1::Int8)::Word8
我希望得到 Word8
值 255(因为 -1 的位表示有符号 int 与无符号 int 中的 255 相同)。
但是,当我执行强制时,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。
最佳答案
就像@kosmikus所说,两者Int8
和Int16
使用 Int#
实现,在 32 位架构上是 32 位宽(Word8
和 Word16
是 Word#
在引擎盖下)。 This comment在 GHC.Prim 中对此进行了更详细的解释。
那么让我们找出为什么这种实现选择会导致您看到的行为:
> let x = unsafeCoerce (-1 :: Int8) :: Word8
> show x
"-1"
Show
Word8
的实例is defined as
instance Show Word8 where
showsPrec p x = showsPrec p (fromIntegral x :: Int)
和 fromIntegral
只是 fromInteger . toInteger
。 toInteger
的定义对于 Word8
是
toInteger (W8# x#) = smallInteger (word2Int# x#)
哪里smallInteger
(在integer-gmp中定义)是
smallInteger :: Int# -> Integer
smallInteger i = S# i
和word2Int#
是 primop类型 Word# -> Int#
- reinterpret_cast<int>
的类似物在C++中。这就解释了为什么你会看到 -1
在第一个示例中:该值只是被重新解释为有符号整数并打印出来。
现在,为什么要添加 0
至x
给你255
?看着Num
Word8
的实例我们看到这个:
(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
加法实际上将值限制在预期范围内。
关于haskell - 显示与 unsafeCoerced 值一起使用时返回错误值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15828947/