2013-09-01 5 views
8

Uczę się, jak niektóre języki programowania przypisują pamięć do danych strukturalnych (w tym przypadku studiuję tablice).Jak wydrukować adres pamięci listy w Haskell

tworzę tablicę, jak pokazano here w sekcji 3.

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

i co próbuję zrobić, to wydrukować adres każdego elementu w pamięci, coś takiego:

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 

Problem, który mam, polega na tym, że nie wiem, jak uzyskać wartość adresu pamięci dla elementu w Haskell.

Czy istnieje funkcja podobna do funkcji Pythona id(object) lub object.object_id Ruby?

+3

Nie jestem pewien, czy to jest możliwe, ale jeśli tak, to adres pamięci może się zmienić w każdej chwili ze względu na przeniesieniu przez garbage collector. –

+0

Tak, ale chcę wydrukować adres pamięci w określonym czasie, więc nie ma znaczenia, czy zmiany w późniejszym wykonaniu –

+0

jest "naprawdęUnsafePtrEquals", "naprawdęUnsafe" sprawia, że ​​wątpię, że GHC wyeksponuje tak wiele magii. – jozefg

Odpowiedz

10

można użyć następującego fragmentu które pożyczonej od opakowania ghc-heap-view (zawiera również alternatywne rozwiązanie używając 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))) 

działa przy pierwszym owijaniu a wewnątrz Ptr' konstruktora, a następnie odlewanie Ptr' a do Word. Ponieważ pole a jest reprezentowane jako wskaźnik, wynikowe słowo zawiera teraz adres obiektu. Zwykłe zastrzeżenia zastosowanie: jest to niebezpieczne, GHC specyficzne, zrywa więzy przejrzystości itp

Testowanie:

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

wyjściowa:

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

Zauważ, że należy użyć unsafeAddr z $!, w przeciwnym razie otrzymasz adres stroju, który oceni się jako a zamiast samego obiektu a:

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

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

wyjściowa:

c: 9465024 
c: 9467001 
c: 9467001 
+1

Schludny pomysł! Możliwe ulepszenia: Word byłby lepszym końcowym typem niż Int (zazwyczaj myślimy o adresach jako nieujemnych).Jeśli zamierzasz to spakować, prawdopodobnie będziesz chciał stworzyć wersję, która "wybierze" przed sprawdzeniem adresu. –

+1

Znaczniki wskaźnika również są tutaj drukowane, powinny być maskowane. –

+0

@NathanHowell Zrobić to w Haskell jest problematyczne, ponieważ szerokość tagów zależy od platformy. 'ghc-heap-view' implementuje' aToWord #' jako primop z tego powodu. –