我正在使用 haskell 简单地实现 LOGO。
对于图形部分,我使用 Gloss,特别是 Graphics.Gloss.Interface.IO.Simulate
模块中的函数 simulateIO
。
我用它来制作一个窗口并保存我的程序的状态。问题在于更新,它使用类型为 ViewPort -> Float -> model -> IO model
的函数,其中 model 是状态的类型。我不使用 Viweport 和 Float 参数。我从控制台读取一行,对其进行解析并对其求值,以获得我在函数结束时返回的新状态。
在第一次执行和更新显示后,它不再更新。 当我打印状态时,我可以看到它正在更新,但显示器没有。 放置一个常量值而不是获取输入可以解决问题,但这也不是很有用:)。
这是我的代码的一小部分:
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
返回 IO Env
有没有办法强制重绘?
编辑
看来我的功能运行良好,确实在修改状态。我认为问题是函数 env2Pic
没有被 simulateIO
函数调用,只是在开始时调用了几次。
我还是不明白为什么。
最佳答案
显然 step 函数不应该阻塞,因此您不应该在该函数中运行像 getLine
这样的阻塞操作。您可以通过在后台线程中运行 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 Gloss,在动画功能中从控制台读取不会更新绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70283210/