haskell - 显示与 unsafeCoerced 值一起使用时返回错误值

标签 haskell ghc coercion

我正在用 Int8Word8 尝试 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所说,两者Int8Int16使用 Int# 实现,在 32 位架构上是 32 位宽(Word8Word16Word# 在引擎盖下)。 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 . toIntegertoInteger的定义对于 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在第一个示例中:该值只是被重新解释为有符号整数并打印出来。

现在,为什么要添加 0x给你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/

相关文章:

Haskell:我如何使用 "2 functions with the same name"?

haskell - 最小 Warp 网络服务器示例

haskell - 真实世界 Haskell,第 5 章,SimpleJSON 编译错误

r - 如何将 readline() 的输入从字符强制转换为数字

linux - 在 Ubuntu Server 12.04 上安装最新 Haskell 源时出错

haskell - 如何在Haskell中创建格型数据结构?

python - 如何告诉Python,当存在冲突时,我们总是希望将 Foo 类型的对象解释为 Bar 类型的对象?

javascript - 为什么 undefined == undefined 是 true 而不是 undefined <= undefined?

haskell - 如何扩展 GHC 的线程状态对象

haskell - 使用 Haskell 类型族或 GADT 的模块化算术?