demathieu
demathieu

Reputation: 489

changing the type of Map.empty in Haskell

I'm making my a minesweeper (game) instead of using a list of list as representation, I'm using different sets that will keep the cells collected by their type.

I'm trying to generate a Map which uses as keys a tuple (x coordinate, y coordinate) as a pair for example like this (0,0). The value of the map will be the amount of neighbors containing a bomb. for example (0,0) 1 meaning cell (0,0) has 1 neighbors with a bomb.

I was able to come up with a dirty way to make it although I'm getting an error on the Map.empty.

Error

setTest.hs:57:70:
    Couldn't match expected type `Map.Map (t0, t0) Int
                                  -> Map.Map (t0, t0) Int'
                with actual type `Map.Map k0 a1'
    In the second argument of `createBoard', namely `Map.empty'
    In the expression: createBoard listOfBombs Map.empty fieldList
    In the expression:
      let
        fieldList = [... | x <- ..., y <- ...]
        nrBombs = round $ fromIntegral (xCoord * yCoord) * 0.20
        listOfBombs
          = Set.fromAscList
              (take nrBombs
               $ nub $ randomRs ((0, 0), (xCoord, yCoord)) (mkStdGen seed))
      in createBoard listOfBombs Map.empty fieldList
Failed, modules loaded: none.

I do understand that the error appears because of the Map.empty having another type than the Map that I use in my functions. However I can not find a way to solve this issue? Also I there a way to link those function smoother together using Map/fold or zip?

--Generate Set with all the neighbors of a cell
neighbours (xCoord,yCoord) = Set.fromAscList $ filter (/=(xCoord,yCoord)) [(x,y) | x <- [(pred xCoord) .. (succ xCoord)], y <- [(pred yCoord) .. (succ yCoord)]]

--Gives back the number of neighbors with a bomb for a cell
giveBackBombsNumber (xCoord,yCoord) listOfBombs =  Set.size $ Set.intersection (neighbours (xCoord,yCoord)) listOfBombs

-- Will insert a cell with the number of bombs around it to the board map.
insertFunction field listOfBombs board =  Map.insert field (giveBackBombsNumber field listOfBombs) board

-- Will create a new Map containing 
createBoard listOfBombs board [] = board
createBoard listOfBombs board (x: xs) = createBoard listOfBombs (insertFunction x listOfBombs)  xs  

testFunction (xCoord,yCoord) seed = let fieldList = [(x,y) | x <- [0 .. xCoord] , y <- [0 .. yCoord]]
                                              nrBombs = round $ fromIntegral (xCoord * yCoord) * 0.20
                                          listOfBombs = Set.fromAscList (take nrBombs  $ nub $ randomRs ((0,0), (xCoord,yCoord)) (mkStdGen seed)) 
                              in createBoard listOfBombs Map.empty fieldList

Upvotes: 0

Views: 494

Answers (1)

melpomene
melpomene

Reputation: 85827

Ignoring the details, your error message reads:

Couldn't match expected type `X -> Y'
            with actual type `Map.Map k0 a1'

i.e. you're using a Map where the code is expecting a function instead.

Likely culprit:

createBoard listOfBombs board (x: xs) = createBoard listOfBombs (insertFunction x listOfBombs)  xs
--                                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You're calling insertFunction with 2 arguments, but it takes 3.

Because of currying, insertFunction x listOfBombs is itself a function (\board -> Map.insert field (giveBackBombsNumber field listOfBombs) board), and you're passing it as the second argument to createBoard (which is board), so ghc thinks board is supposed to be a function and rejects your attempt to give it a Map.

You'll get much better error messages if you put explicit type annotations on your functions.

Upvotes: 5

Related Questions