2013-09-01 2 views
8

Я изучаю, как некоторые языки программирования присваивают память структурированным данным (в этом случае я изучаю массивы).Как напечатать адрес памяти списка в Haskell

Я создаю массив, как показано here в разделе 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.

Есть ли функция, аналогичная функции Python или Ruby's object.object_id?

+3

Я не уверен, если это возможно, но если она есть, адрес памяти может измениться в любое время в связи с переездом сборщиком мусора. –

+0

Да, но я просто хочу напечатать адрес памяти в заданное время, поэтому не имеет значения, если позже изменения в исполнении –

+0

есть 'reallyUnsafePtrEquals',' reallyUnsafe' заставляет меня сомневаться, что GHC разоблачит эту магию. – jozefg

ответ

10

Вы можете использовать следующий фрагмент кода, который я позаимствовал из 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 с $!, в противном случае вы получите адрес 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 
+1

Утонченная идея! Возможные улучшения: Word будет лучшим окончательным типом, чем Int (мы обычно считаем адреса неотрицательными).Если вы собираетесь упаковать это, вы, вероятно, захотите сделать версию, которая '' '' '' 'перед проверкой адреса. –

+1

Здесь также распечатываются теги указателей, они должны быть замаскированы. –

+0

@ NathanHowell Выполнение этого в Haskell проблематично, потому что ширина тега зависит от платформы. По этой причине 'ghc-heap-view' реализует' aToWord # 'как primop. –

Смежные вопросы