Haskell Gloss,在动画功能中从控制台读取不会更新绘图
Posted
技术标签:
【中文标题】Haskell Gloss,在动画功能中从控制台读取不会更新绘图【英文标题】:Haskell Gloss, reading from console within animate function does not update drawing 【发布时间】:2022-01-13 21:19:39 【问题描述】:我正在使用 haskell 进行 LOGO 的简单实现。
对于图形部分,我使用 Gloss,特别是模块 Graphics.Gloss.Interface.IO.Simulate
中的函数 simulateIO
。
我用它来制作一个窗口并保存我的程序的状态。问题在于更新,它使用ViewPort -> Float -> model -> IO 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
函数调用,只是在开始时调用了几次。
我还是不明白为什么。
【问题讨论】:
您是否确认evalPrint
确实返回了更新后的Env
?
是的,我在step
的开头添加了一个print e
,并且每次通话都会发生变化
【参考方案1】:
显然 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))
【讨论】:
试一试,IORef 会像“管道”一样工作吗?没有输入时它的行为如何?我对 Haskell 中的多线程没有太多经验以上是关于Haskell Gloss,在动画功能中从控制台读取不会更新绘图的主要内容,如果未能解决你的问题,请参考以下文章
如何在现有的 Haskell 代码中从 String 转到 Data.ByteString.Lazy?
读 Learn You a Haskell for Great Good!