您可以使用我从ghc-heap-view
包中借来的以下片段(它还包含使用的替代解决方案foreign import prim
):
{-# LANGUAGE MagicHash, BangPatterns #-}
import GHC.Exts
-- A datatype that has the same layout as Word and so can be casted to it.
data Ptr' a = Ptr' a
-- Any is a type to which any type can be safely unsafeCoerced to.
aToWord# :: Any -> Word#
aToWord# a = let !mb = Ptr' a in case unsafeCoerce# mb :: Word of W# addr -> addr
unsafeAddr :: a -> Int
unsafeAddr a = I# (word2Int# (aToWord# (unsafeCoerce# a)))
这通过首先包装a
在Ptr'
构造函数中然后强制转换Ptr' a
为Word
. 由于该a
字段表示为指针,因此结果字现在包含对象的地址。通常的警告适用:这是不安全的、特定于 GHC 的、破坏参考透明度等。
测试:
main :: IO ()
main = do
arr <- newListArray (1,10) [1,2..] :: IO (IOArray Int Int)
a1 <- readArray arr 1
a2 <- readArray arr 2
a1' <- readArray arr 1
putStrLn $ "a1 : " ++ (show . unsafeAddr $! a1)
putStrLn $ "a1 : " ++ (show . unsafeAddr $! a1)
putStrLn $ "a2 : " ++ (show . unsafeAddr $! a2)
putStrLn $ "a2 : " ++ (show . unsafeAddr $! a2)
putStrLn $ "a1': " ++ (show . unsafeAddr $! a1')
输出:
a1 : 16785657
a1 : 16785657
a2 : 16785709
a2 : 16785709
a1': 16785657
请注意,您应该使用unsafeAddr
with $!
,否则您将获得一个 thunk 的地址,该地址将评估为a
而不是a
对象本身:
let a = 1
b = 2
c = a + b
putStrLn $ "c: " ++ (show . unsafeAddr $ c)
putStrLn $ "c: " ++ (show . unsafeAddr $! c)
putStrLn $ "c: " ++ (show . unsafeAddr $! c)
输出:
c: 9465024
c: 9467001
c: 9467001