Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print memory address of a list in Haskell

I'm studying how some programming languages assign memory to structured data (in this case I'm studying arrays).

I'm creating the array as shown here on section 3.

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

And what I'm trying to do is print each element's memory address, something like this:

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

The problem that I have is that I don't know how to get the memory address value for an element in Haskell.

Is there a function similar to Python's id(object) or Ruby's object.object_id?

like image 832
Jose_Sunstrider Avatar asked Sep 01 '13 17:09

Jose_Sunstrider


1 Answers

You can use the following snippet which I borrowed from the ghc-heap-view package (it also contains an alternative solution using 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)))

This works by first wrapping a inside a Ptr' constructor and then casting Ptr' a to Word. Since the a field is represented as a pointer, the resulting word now contains the address of the object. The usual caveats apply: this is unsafe, GHC-specific, breaks referential transparency, etc.

Testing:

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')

Output:

a1 : 16785657
a1 : 16785657
a2 : 16785709
a2 : 16785709
a1': 16785657

Note that you should use unsafeAddr with $!, otherwise you'll be getting an address of a thunk that will evaluate to a instead of the a object itself:

  let a = 1
      b = 2
      c = a + b

  putStrLn $ "c: " ++ (show . unsafeAddr $ c)
  putStrLn $ "c: " ++ (show . unsafeAddr $! c)
  putStrLn $ "c: " ++ (show . unsafeAddr $! c)

Output:

c: 9465024
c: 9467001
c: 9467001
like image 180
Mikhail Glushenkov Avatar answered Sep 22 '22 20:09

Mikhail Glushenkov