1

I'm fairly new to Haskell so excuse my naive way of approach. I am trying to use a "global variable" in a main loop with GTK (gtk2hs) to save/edit a state of a game i am trying to program, as well as a Bool that represents if a game is currently being played.

My current approach is to define a data type for both like so:

data GameBool = GameBool { gameBoolvalue :: Bool } deriving (Show)

main :: IO ()
main = do
  initGUI -- inits GTK
  -- do GUI stuff
  gameBool <- initGameBool
  on button buttonActivated $ callbackNewGame gameBool
  mainGUI  -- runs GTK loop

initGameBool = do
  return $ GameBool False

callbackNewGame :: GameBool -> IO ()
callbackNewGame gameBool = do
  -- Do stuff to check if a game is running in if then else etc.
  updateGameBool gameBool True
  putStrLn "New Game Started"  -- This is not what i do, but represents it well

updateGameBool gameBool b = do
  return $ gameBool { gameBoolvalue = b}

This does not update my gameBoolvalue though, it stays False.

I tried Control.Lens instead of record syntax (the updateGameBool function) but that just ends in a horrible crash that i do not understand. (Yes i added TemplateHaskell to LANGUAGE and performed makeLenses ''GameBool) this:

set gameBoolvalue True gameBool

Results in:

error:
couldn't match type 'Bool'
  with 'GameBool -> Identity (IO a0)'
Expected type: ASetter GameBool (IO a0) a1 Bool
  Actual type: GameBool -> Bool
In the first argument of 'set', namely 'gameBoolvalue'
In a stmt of a 'do' block: set gameBoolvalue True gameBool

I understand my actual type, but not what it wants to tell me with the expected since it doesn't follow the API of set AT ALL, nor is it a type.

I suspect i misunderstand the do block/the interaction/declaration of variables in it. Yes i know they are not really variables, and i would use a loop that simply handes the current values to the next iteration if i could, but GTK makes me unable to. I just want to update the Bool (and my game State, but i think thats the same mistake).

Any help would be appreciated!

Skarrabor
  • 26
  • 2
  • 2
    You need a mutable reference (pointer), so that you can update the state. Chencg your function to `callbackNewGame :: IORef GameBool -> IO ()`, and adapt the rest of your code accordingly (create the reference with `newIORef`, etc.). You are inside IO, so you can do things imperatively. – chi Aug 22 '20 at 18:48
  • Indeed IORef/MVar is the answer i was looking for. Thanks! – Skarrabor Aug 23 '20 at 15:56

0 Answers0