
module Pointer where

import Control.Monad.State
import Data.Map (Map)
import qualified Data.Map as Map

newtype Ptr a = Ptr { rawPtr :: Int }
    deriving (Eq, Ord)

data Heap a = Heap { nextPtr :: Int
		   , thunks  :: Map (Ptr a) a
		   }

type HeapM a = State (Heap a)

runHeap :: HeapM a b -> b
runHeap h = evalState h (Heap 0 Map.empty)

deref :: Ptr a -> HeapM a a
deref p = do
    heap <- gets thunks
    return $ heap Map.! p

store :: Ptr a -> a -> HeapM a ()
store p v = modify $ \h -> h { thunks = Map.insert p v $ thunks h }

free :: Ptr a -> HeapM a ()
free p = modify $ \h -> h { thunks = Map.delete p $ thunks h }

fresh :: HeapM a (Ptr a)
fresh = do
    h <- get
    let n = nextPtr h
    put $ h { nextPtr = n + 1 }
    return $ Ptr n

onThunk :: Ptr a -> (a -> HeapM a a) -> HeapM a a
onThunk p f = do
    v <- deref p
    w <- f v
    store p w
    return w

alloc :: a -> HeapM a (Ptr a)
alloc v = do
    p <- fresh
    store p v
    return p

