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))