问题
I have to implement a gameboard for 2048. I declared it:
type Board = [[Int]]
In order to add a new random value in a random cell I must check the value in that cell, but I don't know how to get the value. I've seen different examples using a monad, but I don't know how to use Monad
and I was wondering if there is another way to do this.
Can anyone help me with an example?
Thanks!
回答1:
Well, as for checking the value in a particular cell – that's just list-indexing, you can simply use !!
. Since the list is nested you need two lookups, first the row then the column/cell.
type CellId = (Int,Int)
cellAt :: Board -> CellId -> Int
cellAt rows (idy, idx) = rows !! idy !! idx
I bit less obvious is updating. To do that in a functional style you need a function like
updataCellAt :: CellId -> Int -> Board -> Board
that takes a board as an argument, and returns a modified board.
Modifying a list is easy only at one spot: the head.
replaceHead :: a -> [a] -> [a]
replaceHead _ [] = []
replaceHead x (_:xs) = x:xs
To modify an arbitrary spot, the best thing is to first split up the list in everything before that spot, and everything form there on (so the second list has the spot as its head).
replaceAt :: Int -> a -> [a] -> [a]
replaceAt i x xs = let (prev, remain) = splitAt i xs
in prev ++ replaceHead x remain
Now, this is not very flexible: you're simply throwing away the replaced element, but in general you might want to only apply a transformation to it.
modifyHead :: (a->a) -> [a] -> [a]
modifyHead _ [] = []
modifyHead mdf (x:xs) = mdf x : xs
modifyAt :: Int -> (a->a) -> [a] -> [a]
modifyAt i mdf xs = let (prev, remain) = splitAt i xs
in prev ++ modifyHead mdf remain
This one can now easily be used to modify a nested list, like your board:
modifyCellAt :: CellId -> (a->a) -> [[a]] -> [[a]]
modifyCellAt (iy, ix) mdf = modifyAt iy (\row -> modifyAt ix mdf row)
-- or short: modifyAt iy $ modifyAt ix mdf
来源:https://stackoverflow.com/questions/23427728/how-to-extract-the-value-from-a-certain-position-in-a-matrix-in-haskell