2

我正在haskell中简单地实现LOGO。

对于我使用 Gloss 的图形部分,特别是simulateIO模块中的函数Graphics.Gloss.Interface.IO.Simulate

我用它来制作一个窗口并保存我的程序的状态。问题在于更新,它使用类型的函数,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函数调用,只是在开始时调用了几次。

我仍然无法弄清楚为什么。

4

1 回答 1

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))
于 2021-12-10T09:29:01.943 回答