Haskell Gloss,在 animate 函数中从控制台读取不会更新绘图
Haskell Gloss, reading from console within animate function does not update drawing
我正在 haskell.
中简单实现 LOGO
对于图形部分,我使用 Gloss,特别是模块 Graphics.Gloss.Interface.IO.Simulate
中的函数 simulateIO
。
我用它来制作 window 并保存我的程序状态。问题在于更新,它使用 ViewPort -> Float -> model -> IO model
类型的函数,其中模型是状态的类型。我不使用 Viweport 和 Float 参数。我从控制台读取了一行,对其进行解析并对其求值以获得函数末尾 return 的新状态。
显示第一次执行更新后,不再更新。
当我打印状态时,我可以看到它正在更新,但显示器没有。
放置一个常量值而不是获取输入可以解决问题,但这也不是很有用:)。
这是我的代码的一小部分:
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
有没有办法强制重绘?
编辑
看来我的功能运行良好,确实在修改状态。我认为问题是函数 env2Pic
没有被 simulateIO
函数调用,一开始只调用了几次。
我还是不明白为什么。
显然 step 函数不应该阻塞,所以你不应该 运行 在该函数中阻塞像 getLine
这样的操作。您可以通过在后台线程中 运行ning getLine
来解决它。这是一个最小的工作示例:
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))
我正在 haskell.
中简单实现 LOGO对于图形部分,我使用 Gloss,特别是模块 Graphics.Gloss.Interface.IO.Simulate
中的函数 simulateIO
。
我用它来制作 window 并保存我的程序状态。问题在于更新,它使用 ViewPort -> Float -> model -> IO model
类型的函数,其中模型是状态的类型。我不使用 Viweport 和 Float 参数。我从控制台读取了一行,对其进行解析并对其求值以获得函数末尾 return 的新状态。
显示第一次执行更新后,不再更新。 当我打印状态时,我可以看到它正在更新,但显示器没有。 放置一个常量值而不是获取输入可以解决问题,但这也不是很有用:)。
这是我的代码的一小部分:
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
有没有办法强制重绘?
编辑
看来我的功能运行良好,确实在修改状态。我认为问题是函数 env2Pic
没有被 simulateIO
函数调用,一开始只调用了几次。
我还是不明白为什么。
显然 step 函数不应该阻塞,所以你不应该 运行 在该函数中阻塞像 getLine
这样的操作。您可以通过在后台线程中 运行ning getLine
来解决它。这是一个最小的工作示例:
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))