Home > Mobile >  Haskell Gloss, reading from console within animate function does not update drawing
Haskell Gloss, reading from console within animate function does not update drawing

Time:12-12

I'm working in a simple implementation of LOGO in haskell.

For the graphic part I'm using Gloss, in particular the function simulateIO from the module Graphics.Gloss.Interface.IO.Simulate.

I use it to make a window and save the state of my program. The problem is with the updates, it uses a function of type ViewPort -> Float -> model -> IO model where model is the type of the state. I don't use the Viweport and Float arguments. I read a line from console, parse it and evaluate it to get a new state that I return at the end of the function.

After the first execution and update of the display, it doesn't update anymore. When I print the state I can see it is updating, but the display does not. Putting a constant value instead of getting the input fixes the problem, but that is nor very useful :).

Here is a brief part of my code:

runProgram :: Display -> IO ()
runProgram d = simulateIO d white 10 defaultEnv env2Pic step

env2Pic :: Env -> IO Picture
env2Pic e =
   ...
   in return $ pictures piccc

step :: ViewPort -> Float -> Env -> IO Env
step v f e = do
  minput <- getLine
  case minput of
    "" -> step v f e
    _ -> case parserComm minput of
      Nothing -> print "no parse" >> step v f e
      Just cms -> evalPrint e cms

evalPrint returns IO Env

Is there a way to force the redrawing?

EDIT It seems that my function is working well and the state is indeed being modified. I think the problem is that the function env2Pic doesn't get called by the simulateIO function, only a few times at the start.

I still can't figure out why.

CodePudding user response:

Apparently the step function is not supposed to block, so you should not run blocking operations like getLine in that function. You can work around it by running getLine in a background thread. Here is a minimal working example of that:

import Control.Concurrent (forkIO)
import Control.Monad (forever)
import Data.IORef (IORef, atomicWriteIORef, newIORef, readIORef)
import Graphics.Gloss (Display (InWindow), Picture (Text), white)
import Graphics.Gloss.Interface.IO.Simulate
  ( ViewPort,
    simulateIO,
  )

runProgram :: IORef String -> Display -> IO ()
runProgram r d = simulateIO d white 10 "" env2Pic (step r)

type Env = String

env2Pic :: Applicative f => Env -> f Picture
env2Pic e = pure (Text e)

step :: IORef String -> ViewPort -> Float -> Env -> IO Env
step r _ _ _ = readIORef r

background :: IORef String -> IO b
background r = forever $ do
  x <- getLine
  atomicWriteIORef r x

main :: IO ()
main = do
  r <- newIORef ""
  forkIO $ background r
  runProgram r (InWindow "test" (500, 500) (100, 100))
  • Related