2012-04-18 2 views
1

Я переписываю игру, я задал вопрос «How can I iterate over a quadruple linked 2-dimensional grid of data as if it were a 2-dimensional array?», для Хаскелла.Как преобразовать индексы в изменяемый массив в ссылки на источники в Haskell?

Для создания сетки данных в первую очередь я использовал очень императивный алгоритм стиля, показанный ниже. Ключевая функция, на которую он опирается, заключается в том, что я могу взять индекс в массив и создать ссылку из него. Пример: «& массив [x] [y]».

Мне нужно уметь индексировать в изменчивый массив и делать из него ссылку в Haskell. Таким образом, тип подписи может быть

convertToSTRef :: i -> STArray s i a -> ST s (STRef s a) 

Я просмотрел документацию, пытались как hoogle и hayoo, и не нашел способ сделать это.

P.S. Альтернативно, если бы у кого-то был другой алгоритм, который я мог бы использовать, это было бы здорово.

P.S.S. Простой императивный алгоритм.

const size_t rows = 20; 
const size_t columns = 59; 

block tiles[columns][rows]; 
block * const start = &tiles[columns/2][rows/2]; 

for (size_t x = 0; x < columns; ++x) 
for (size_t y = 0; y < rows; ++y) 
{ 
    tiles[x][y].floor = '^'; 
    tiles[x][y].inhabitant = WALL; 
    tiles[x][y].side_block[EAST] = (x + 1 < columns) ? &tiles[x + 1][y] : NULL; 
    tiles[x][y].side_block[SOUTH] = (y + 1 < rows) ? &tiles[x][y + 1] : NULL; 
    tiles[x][y].side_block[WEST] = (x > 0) ? &tiles[x - 1][y] : NULL; 
    tiles[x][y].side_block[NORTH] = (y > 0) ? &tiles[x][y - 1] : NULL; 
} 
+0

Вам нужно изменить, где эти ссылки указывают на некоторое позднее время? Если нет, нет необходимости хранить их вообще, и вы можете просто использовать функцию 'sideBlock :: Direction -> (Int, Int) -> Maybe (Int, Int)' вместо этого. – hammar

ответ

5

Вы можете представлять «указатель» с помощью курсора, то есть структуры данных, содержащей ссылку на массив и смещение.

data Cursor t i a = Cursor (t i a) i 

makeCursor :: STArray s i a -> i -> Cursor (STArray s) i a 
makeCursor = Cursor 

readCursor :: Ix i => Cursor (STArray s) i a -> ST s a 
readCursor (Cursor arr i) = readArray arr i 

writeCursor :: Ix i => a -> Cursor (STArray s) i a -> ST s() 
writeCursor x (Cursor arr i) = writeArray arr i x 

Невозможно указать на внутренность собранного мусора объекта в GHC. Сборщик мусора не может понять таких указателей. Если массив перемещается сборщиком мусора, сборщик мусора не может соответствующим образом обновлять такие указатели. Если сборщику мусора присваивается указатель на середину массива, он не может сканировать весь массив, потому что он не может найти начало массива.

+0

Я думал о простом хранении индексов в массивах, но логичнее (ваша идея), чтобы хранить указатель на массив и индекс вместе. –