首页 > 解决方案 > 如何使用 IO 和 GTK 更新 main 中的“变量”

问题描述

我对 Haskell 还很陌生,所以请原谅我天真的方法。我试图在 GTK (gtk2hs) 的主循环中使用“全局变量”来保存/编辑我正在尝试编程的游戏的状态,以及表示当前是否正在玩游戏的 Bool。

我目前的方法是为两者定义数据类型,如下所示:

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}

不过,这不会更新我的 gameBoolvalue,它保持为 False。

我尝试了 Control.Lens 而不是记录语法(updateGameBool 函数),但这只会以我不理解的可怕崩溃告终。(是的,我将 TemplateHaskell 添加到 LANGUAGE 并执行 makeLenses ''GameBool)这个:

set gameBoolvalue True gameBool

结果是:

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

我了解我的实际类型,但不是它想要告诉我的预期类型,因为它不遵循 set AT ALL 的 API,也不是类型。

我怀疑我误解了 do 块/其中变量的交互/声明。是的,我知道它们并不是真正的变量,如果可以的话,我会使用一个简单地将当前值传递给下一次迭代的循环,但 GTK 让我无法做到。我只想更新布尔(和我的游戏状态,但我认为那是同样的错误)。

任何帮助,将不胜感激!

标签: variableshaskellioimmutability

解决方案


推荐阅读