9

我正在研究一些编程语言如何为结构化数据分配内存(在这种情况下我正在研究数组)。

我正在创建数组,如第 3 节所示

import Data.Array.IO
arr <- newArray (1,10) 37 :: IO (IOArray Int Int) --Sets default to 37

我要做的是打印每个元素的内存地址,如下所示:

Array Start: <dec addr> | <hex addr> --Shows where the array itself is
Array 1: <dec addr> | <hex addr> --Memory address of the first element
Array 2: <dec addr> | <hex addr| --Memory address of the second element

我遇到的问题是我不知道如何获取 Haskell 中元素的内存地址值。

是否有类似于 Pythonid(object)或 Ruby 的功能object.object_id

4

1 回答 1

12

您可以使用我从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)))

这通过首先包装aPtr'构造函数中然后强制转换Ptr' aWord. 由于该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

请注意,您应该使用unsafeAddrwith $!,否则您将获得一个 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
于 2013-09-01T23:05:37.997 回答