This is not an appropriate solution to your problem. It is impossible* to extract data from the IO monad, because that's not it's purpose. You should instead look into using the State monad family (or it's close cousins StateT), which lets you carry a mutable value along with you through the program, like so:
data Game = Game { health :: Int, ... }
type GameState = State Game
Then to read your value from the main thread, you use:
gameloop :: GameState ()
gameloop = do
currentHealth <- gets health
pure ()
To update the health, you need a short function:
updateHealth :: Int -> Game -> Game
updateHealth newHealth game = game { health = newHealth }
Then you can set health to 10 with:
gameloop :: GameState ()
gameloop = do
modify $ updateHealth 10
pure ()
Usage examples:
> evalState (gets health) (Game { health = 10 })
10
> evalState (modify (updateHealth 20) >> gets health) (Game { health = 10 })
20
* It is actually possible to extract values from IO using unsafePerformIO, but as the name suggests, it is unsafe to do so unless you really know what you're doing.
IOmeans you define a recipe to obtain the value, it is not the value itself.GameContextthat contains data about the state of the game.